Solution
- 由于没有环,可以看出食物网的分级结构,令生产者-初级消费者-...等级越来越高
- 对于每种生物,能使它灭绝的等级最低的生物至多有一种,为能使 每种吃它的生物 灭绝的等级最低的生物
- 可以建一棵灭绝树,树上每个节点的父亲即为能使它灭绝的等级最低的生物
- 求父亲即为求每种吃它的生物在灭绝树上对应的点的 LCA
- 可以看出求某个点的父亲时每种吃它的生物的父亲应已求出
- 在原食物网上跑一个拓扑,由于每种吃它的生物的拓扑排序必然在它前面,可以按这个顺序建树
- 为将森林化成树,将原食物网上所有入度为 0 的点的父亲指向 0
Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N=5e5+10;
int ru[N],top[N];
int n,m,root,dep[N],fa[N][20],num,sum,si[N],d[N];
vector <int> l1[N],l2[N];
queue <int> q;
int lca(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
for(int i=19;i>=0;i--)
if(dep[fa[y][i]]>=dep[x]) y=fa[y][i];
if(y==x) return x;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int dfs(int u)
{
int size=l2[u].size();
for(int i=0;i<size;i++)
si[u]+=dfs(l2[u][i]);
return si[u];
}
int main()
{
scanf("%d",&n);
for(int x=1,y;x<=n;x++)
{
si[x]=1;
while(scanf("%d",&y) && y)
l1[y].push_back(x),ru[x]++;
if(ru[x]==0) q.push(x);
else top[x]=-1;
}
while(!q.empty())
{
int u=q.front();
q.pop();
l2[top[u]].push_back(u);
dep[u]=dep[top[u]]+1,fa[u][0]=top[u];
for(int i=1;i<20;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
int size=l1[u].size();
for(int i=0;i<size;i++)
{
int v=l1[u][i];
if(top[v]==-1) top[v]=u;
else top[v]=lca(top[v],u);
if(--ru[v]==0) q.push(v);
}
}
dfs(0);
for(int i=1;i<=n;i++)
printf("%d\n",si[i]-1);
return 0;
}
来源:https://www.cnblogs.com/hsez-cyx/p/12393719.html