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;
}

  

 

posted @ 2015-02-14 22:46  Claris  阅读(491)  评论(0编辑  收藏  举报