灾难
题目传送门
大佬的博客
对于一个节点来说,当它所有的食物的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;
}