题目:洛谷P2597、BZOJ2815(然而此处并没有题面)、codevs1210
题目大意:给你一个食物网,要你求每个生物的“毁灭值”(毁灭值为该生物灭绝后,其他跟着它灭绝的生物的总数)。
解题思路:拓扑排序+LCA。
先假设所有生产者都吃“太阳”,然后对它们进行拓扑排序。以拓扑序依次加点,每次将要加的点与所有父亲求LCA,此时LCA或LCA的任一父亲节点死亡,则该点灭绝。所以直接把该点变为LCA的子节点即可。此时每个节点的毁灭值为以它为根的子树的节点的个数。
不过我的代码在codevs上莫名的RE了,知道原因的可以告诉我。
C++ Code:
#include<cstdio> #include<queue> #include<vector> #include<algorithm> using namespace std; int n; vector<int>p[65536],c[65536],nc[65536]; queue<int>tp; int has[65536],dep[65536],s[65536][18],ans[65536]; void topo(){ queue<int>q; q.push(0); while(!q.empty()){ int v=q.front(); q.pop(); tp.push(v); for(int i=0;i<c[v].size();i++) if(!--has[c[v][i]])q.push(c[v][i]); } } int LCA(int x,int y){ int i,j; if(x==-1)return y; if(dep[x]<dep[y])swap(x,y); for(i=0;(1<<i)<=dep[x];i++);i--; for(j=i;j>-1;j--){ if(dep[x]-(1<<j)>=dep[y])x=s[x][j]; } if(x==y)return x; for(j=i;j>=0;j--) if(s[x][j]!=s[y][j]) x=s[x][j],y=s[y][j]; return s[x][0]; } void getans(int x){ for(int i=0;i<nc[x].size();i++){ getans(nc[x][i]); ans[x]+=ans[nc[x][i]]+1; } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int x; while(scanf("%d",&x),x){ p[i].push_back(x); c[x].push_back(i); has[i]++; } if(!p[i].size()){ p[i].push_back(0); c[0].push_back(i); has[i]=1; } } topo(); while(!tp.empty()){ int u=tp.front();tp.pop(); int lca=-1; for(int i=0;i<p[u].size();i++)lca=LCA(lca,p[u][i]); nc[lca].push_back(u); s[u][0]=lca; dep[u]=dep[lca]+1; for(int i=1;(1<<i)<=dep[u];i++)s[u][i]=s[s[u][i-1]][i-1]; } getans(0); for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
时间: 2024-10-12 02:54:55