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