bzoj2815 灾难
我们需要建立一个叫灭绝树的东西,灭绝树,顾名思义,就是树上的一个节点的灭绝会且仅会导致以它为根的子树的灭绝。
如果我们把这颗树建立出来,那么只需要跑一遍dfs求子树大小就可以解决这道题。
那么怎么建这个灭绝树呢。
我们先拓扑排序,按照拓扑序区建树,一个动物可以吃的所有动物(在灭绝树上)的lca就是他在灭绝树上的父亲。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=65534+10; int n,rd[maxn],ans[maxn],mi[20]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } int fir[maxn],to[50*maxn],nxt[50*maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; } int dep[maxn],fa[maxn][20]; int getlca(int x,int y) { if(dep[x]!=dep[y]) { if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y]; for(int i=17;i>=0&&cha;--i) if(cha>=mi[i]) { x=fa[x][i]; cha-=mi[i]; } } if(x==y)return x; for(int i=17;i>=0;--i) if(fa[x][i]!=fa[y][i]) { x=fa[x][i];y=fa[y][i]; } return fa[x][0]; } int zz[maxn]; void tp() { int s=1,t=0,x,y,z; for(int i=1;i<=n;++i) fa[i][0]=-1; for(int i=1;i<=n;++i) if(rd[i]==0) zz[++t]=i,fa[i][0]=0; while(s<=t) { x=zz[s++];dep[x]=dep[fa[x][0]]+1; for(int i=1;i<=17;++i) fa[x][i]=fa[fa[x][i-1]][i-1]; for(y=fir[x];y;y=nxt[y]) { z=to[y];rd[z]--; if(rd[z]==0) zz[++t]=z; if(fa[z][0]==-1) fa[z][0]=x; else fa[z][0]=getlca(fa[z][0],x); } } for(int i=t;i;--i) ans[fa[zz[i]][0]]+=ans[zz[i]]+1; } int main() { n=read(); int x; for(int i=1;i<=n;++i) { x=read(); while(x) add(x,i),rd[i]++,x=read(); } mi[0]=1;for(int i=1;i<=17;++i) mi[i]=mi[i-1]<<1; tp(); for(int i=1;i<=n;++i) printf("%d\n",ans[i]); return 0; }
弱者就是会被欺负呀