BZOJ3673 : 可持久化并查集

题目没有强制在线!

考虑离线做法。

把操作建立成一棵树的结构,然后按照欧拉序遍历,每次转移要么是一次合并操作,要么是一次撤销合并操作,可以看成是分离操作。

用LCT维护集合,合并就是加边,分离就是删边。

时间复杂度$O(m\log n)$

 

#include<cstdio>

#define N 20010

int n,m,i,op,x,y,id[N],ans[N],last,g[N],nxt[N],v[N],q[N],w[N],ed,G[N],NXT[N],V[N],Q[N],W[N],ED,f[N],son[N][2],tmp[N];bool rev[N];

inline void swap(int&x,int&y){int z=x;x=y;y=z;}

inline bool isroot(int x){return !f[x]||(son[f[x]][0]!=x&&son[f[x]][1]!=x);}

inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}

inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}

inline void rotate(int x){

  int y=f[x],w=son[y][1]==x;

  son[y][w]=son[x][w^1];

  if(son[x][w^1])f[son[x][w^1]]=y;

  if(f[y]){

    int z=f[y];

    if(son[z][0]==y)son[z][0]=x;

    if(son[z][1]==y)son[z][1]=x;

  }

  f[x]=f[y];f[y]=x;son[x][w^1]=y;

}

inline void splay(int x){

  int s=1,i=x,y;tmp[1]=i;

  while(!isroot(i))tmp[++s]=i=f[i];

  while(s)pb(tmp[s--]);

  while(!isroot(x)){

    y=f[x];

    if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}

    rotate(x);

  }

}

inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y;}

inline int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}

inline void makeroot(int x){access(x);splay(x);rev1(x);}

inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}

inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}

inline void cut(int x,int y){makeroot(x);cutf(y);}

inline void add(int x,int y,int a,int b){v[++ed]=y;q[ed]=a;w[ed]=b;nxt[ed]=g[x];g[x]=ed;}

inline void ADD(int x,int y,int a,int b){V[++ED]=y;Q[ED]=a;W[ED]=b;NXT[ED]=G[x];G[x]=ED;}

void dfs(int x){

  int i;

  for(i=G[x];i;i=NXT[i])ans[V[i]]=root(Q[i])==root(W[i]);

  for(i=g[x];i;i=nxt[i])if(root(q[i])!=root(w[i]))link(q[i],w[i]),dfs(v[i]),cut(q[i],w[i]);else dfs(v[i]);

}

int main(){

  for(scanf("%d%d",&n,&m),i=1;i<=m;ans[i++]=-1){

    scanf("%d",&op);

    if(op==1)scanf("%d%d",&x,&y),add(last,id[i]=i,x,y),last=i;

    if(op==2)scanf("%d",&x),last=id[i]=id[x];

    if(op==3)scanf("%d%d",&x,&y),ADD(last,i,x,y),id[i]=last;

  }

  for(dfs(0),i=1;i<=m;i++)if(~ans[i])printf("%d\n",ans[i]);

  return 0;

}

  

 

你可能感兴趣的:(并查集)