ZJOI2012 灾难
我们考虑拓扑排序,那么我们可以构造一个树结构,使其满足:
当一个点灭亡,其子树也灭亡。
我们考虑对一个点的所有边求lca,把这个点加到lca的子树里就好了。
答案就是子树的大小-1(减掉自己)
#include<bits/stdc++.h> #define eho(X,x) for(int i=X.head[x];i;i=X.net[i]) #define sight(c) ('0'<=c&&c<='9') #define pc printf using namespace std; #define N 100007 inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar()) x=x*10+c-48; } int v,n,t,dep[N],to[N],q[N],be,tog,f[N][21],LA,siz[N]; struct G{ int fall[N<<1],head[N],net[N],tot; inline void add(int x,int y){ fall[++tot]=y; net[tot]=head[x]; head[x]=tot; } }G1,G2,G3; int lca(int x,int y){ if (dep[x]<dep[y]) swap(x,y); for (int i=18;~i;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; if (x==y) return x; for (int i=18;~i;i--) if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void dfs(int x){ siz[x]=1; eho(G2,x) dfs(G2.fall[i]),siz[x]+=siz[G2.fall[i]]; } void write(int x){if (x<10){putchar(48+x);return;}write(x/10);putchar(48+x%10);} inline void writeln(int x){if (x<0) putchar('-'),x=-x; write(x); putchar('\n');} int main () { // freopen("a.in","r",stdin); read(n); for (int i=1;i<=n;i++) while (read(t),t) G1.add(t,i),G3.add(i,t),to[i]++; for (int i=1;i<=n;i++) if (!to[i]) q[++tog]=i; // cerr<<"rrsb"<<endl; while (tog<n) { ++be; eho(G1,q[be]) { to[G1.fall[i]]--; if (!to[G1.fall[i]]) q[++tog]=G1.fall[i];} } // cerr<<"rrsb"<<endl; for (int t=1;t<=n;t++) { v=q[t]; if (!G3.head[v]) {G2.add(0,v); dep[v]=1;continue;} else {LA=G3.fall[G3.head[v]];} eho(G3,v) LA=lca(LA,G3.fall[i]); G2.add(LA,v); f[v][0]=LA; dep[v]=dep[LA]+1; for(int i=1;i<=18;i++) f[v][i]=f[f[v][i-1]][i-1]; } dfs(0); for (int i=1;i<=n;i++) writeln(siz[i]-1); return 0; }