BZOJ2610 : [Poi2003]Monkeys
考虑离线,将删边操作倒过来变成加边,等价于询问每个点什么时候与1连通
使用并查集维护,每次合并时如果有一边是1所在连通块,就把另一边的所有点的答案更新
#include<cstdio> #define N 200010 int n,m,i,j,x,y,son[N][2],del[N][2],q[N<<1][2],f[N],ans[N],g[N],nxt[N<<1],v[N<<1],ed; inline void read(int&a){ char c; while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-'))); if(c!='-')a=c-'0';else{a=-1;getchar();return;} while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0'; } inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x,int pre,int y){ ans[x]=y; for(int i=g[x];i;i=nxt[i])if(v[i]!=pre)dfs(v[i],x,y); } int F(int x){return f[x]==x?x:f[x]=F(f[x]);} inline void merge(int x,int y,int z){ if(y<0)return; if(F(x)==F(y))return; if(f[x]==F(1))dfs(y,0,z);else if(f[y]==F(1))dfs(x,0,z);else add(x,y),add(y,x); f[f[x]]=f[y]; } int main(){ read(n),read(m); for(i=1;i<=n;i++)read(son[i][0]),read(son[i][1]),f[i]=i; for(i=0;i<m;i++)read(x),read(y),del[q[i][0]=x][q[i][1]=y-1]=1; for(i=1;i<=n;i++)for(j=0;j<2;j++)if(!del[i][j])merge(i,son[i][j],-1); for(i=m-1;~i;i--)merge(q[i][0],son[q[i][0]][q[i][1]],i); for(puts("-1"),i=2;i<=n;i++)printf("%d\n",ans[i]); return 0; }