灾难

题目传送门

大佬的博客
对于一个节点来说,当它所有的食物的LCA灭绝时,它才会灭绝。因此,将它直接连向这个LCA。然后有向图就变成了一棵树,每个节点的子树的大小-1就是该节点的答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 70005;
int n,m,tot,head[N],deg[N],dep[N];
struct edge{
	int node,next;
}e[N<<1],t[N<<1];
queue<int> q;
int head2[N],tot2,siz[N],f[N][22];
bool vis[N],vis2[N];
void add(int x,int y)
{
	e[++tot].node=y;
	e[tot].next=head[x];
	head[x]=tot;
}
void add2(int x,int y)
{
	t[++tot2].node=y;
	t[tot2].next=head2[x];
	head2[x]=tot2;
}
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=20;i>=0;i--)
	 if(dep[f[x][i]]>=dep[y])
	  x=f[x][i];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
	if(f[x][i]!=f[y][i])
	 x=f[x][i],y=f[y][i];
	return f[x][0];
}
void bfs()
{
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].node;
			if(!vis[v])
			 vis[v]=1,f[v][0]=u;
			else f[v][0]=lca(f[v][0],u);//如果v之前作为子节点被扩展过
			deg[v]--;//u,和fa[v][0]一定都在队列里  
			if(!deg[v])//所以他们的祖先一定被构建了出来  妙啊!  
			{
				q.push(v);//当找到它在支配树上的父节点时,才把它加到队列里。  
				add2(f[v][0],v);
				dep[v]=dep[f[v][0]]+1;
				for(int i=1;i<=20;i++)
				 f[v][i]=f[f[v][i-1]][i-1];
			}
		}
	}
}
void dfs(int u,int fa)
{
	siz[u]=1; //vis2[u]=1;
	for(int i=head2[u];i;i=t[i].next)//head[u]
	{
		int v=t[i].node;//e[i].node
	//	if(vis2[v]) continue;
		dfs(v,u);
		siz[u]+=siz[v];
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		while(1)
		{
			scanf("%d",&m);
			if(m==0) break;
			deg[i+1]++;
			add(m+1,i+1);
		}
	}
	for(int i=1;i<=n;i++)
	 if(!deg[i+1])
	  add(1,i+1), deg[i+1]++;//漏掉deg[i+1]++ 
	dep[1]=1; q.push(1);
	bfs(); dfs(1,0);
	for(int i=1;i<=n;i++)
	 printf("%d\n",siz[i+1]-1);
	return 0;
}
posted @ 2019-05-21 20:26  蟹蟹王  阅读(141)  评论(0编辑  收藏  举报