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