[ZJOI2012]灾难 发表于 2018-07-22 | 分类于 OI 字数统计: 484 | 阅读时长 ≈ 3 支配树的证明我意会了一下,并不会证这里稍微理一下DAG中支配树的构造 拓扑排序 对于每个点,求其所有入边的LCA,将其作为LCA的儿子 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283#include<cstdio>#include<queue>#include<vector>using namespace std;const int N=100050,rt=0;;int n,w[N],d[N],log[N],dep[N],sz[N],fa[N][25];queue<int> Q;vector<int> e[N],f[N],g[N];inline int read(){ register int x=0,t=1; register char ch=getchar(); while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); if (ch=='-') t=-1,ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return x*t;}int LCA(int u,int v){ if (dep[u]<dep[v]) swap(u,v); for(int i=log[dep[u]];i>=0;i--) if (((dep[u]-dep[v])>>i)&1) u=fa[u][i]; if (u==v) return u; for(int i=log[dep[u]];i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0];}void find(int o){ int pre=f[o][0]; for(int i=1;i<f[o].size();i++) pre=LCA(pre,f[o][i]); g[pre].push_back(o); dep[o]=dep[pre]+1; fa[o][0]=pre; for(int i=1;i<=log[dep[o]];i++) fa[o][i]=fa[fa[o][i-1]][i-1];}void dfs(int o){ sz[o]=1; for(int i=0;i<g[o].size();i++) { int to=g[o][i]; dfs(to); sz[o]+=sz[to]; }}int main(){ n=read(); for(int i=1;i<=n;i++) log[i]=log[i-1]+(1<<log[i-1]==i); for(int x,i=1;i<=n;i++) { while (x=read()) { e[x].push_back(i); f[i].push_back(x); d[i]++; } } for(int i=1;i<=n;i++) if (!d[i]) { f[i].push_back(rt); Q.push(i); } for(int i=1;i<=n;i++) { int x=Q.front(); for(int k=0;k<e[x].size();k++) { int to=e[x][k]; if (--d[to]==0) Q.push(to); } find(x),Q.pop(); } dfs(rt); for(int i=1;i<=n;i++) printf("%d\n",sz[i]-1); return 0;}