可撤销并查集
按秩合并来保证复杂度正确。
每次合并的时候记录一下是是怎么连边的,撤销的时候断开这条边就行了。
struct DSU{
int n,f[N],siz[N];
int stk[N],top;
void init(int x){n=x;for(int i=1;i<=x;i++)f[i]=i,siz[i]=1;}
void merge(int t,int x,int y){
while(f[x]!=x)x=f[x];
while(f[y]!=y)y=f[y];
if(x==y)return ;
if(siz[x]>siz[y])std::swap(x, y);
siz[y]+=siz[x];f[x]=y;stk[++top]=x;
op[t]=0;
}
void pop(){
int x=stk[top--];
siz[f[x]]-=siz[x];f[x]=x;
}
int query(int x,int y){
while(f[x] != x)x=f[x];
while(f[y] != y)y=f[y];
return x==y;
}
};