一、题目
二、解法
并查集最重要的就是 f a fa fa数组,我们可以拿主席树来维护这个 f a fa fa,并且每次改点只需要改一个,为保证时间复杂度我们再维护一个 d e p dep dep来做启发式合并,这就变成了一个单点修改,单点查询的主席树了。
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 200005;
const int N = 30*M;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,cnt,rt[M],fa[N],dep[N],ls[N],rs[N];
void build(int &i,int l,int r)
{
i=++cnt;
if(l==r)
{
fa[i]=l;
return ;
}
int mid=(l+r)>>1;
build(ls[i],l,mid);
build(rs[i],mid+1,r);
}
void upd(int &x,int y,int l,int r,int p,int v)
{
x=++cnt;
if(l==r)
{
fa[x]=v;
return ;
}
ls[x]=ls[y];rs[x]=rs[y];
int mid=(l+r)>>1;
if(mid>=p) upd(ls[x],ls[y],l,mid,p,v);
else upd(rs[x],rs[y],mid+1,r,p,v);
}
void add(int x,int l,int r,int p)
{
if(l==r)
{
dep[x]++;
return ;
}
int mid=(l+r)>>1;
if(mid>=p) add(ls[x],l,mid,p);
else add(rs[x],mid+1,r,p);
}
int ask(int x,int l,int r,int p)
{
if(l==r) return x;
int mid=(l+r)>>1;
if(mid>=p) return ask(ls[x],l,mid,p);
return ask(rs[x],mid+1,r,p);
}
int find(int E,int x)
{
int t=ask(E,1,n,x);
if(fa[t]==x) return t;
return find(E,fa[t]);
}
signed main()
{
n=read();m=read();
build(rt[0],1,n);
for(int i=1;i<=m;i++)
{
int op=read();
if(op==1)
{
int u=read(),v=read();
rt[i]=rt[i-1];
int x=find(rt[i],u),y=find(rt[i],v);
if(fa[x]==fa[y]) continue;
if(dep[x]>dep[y]) swap(x,y);
upd(rt[i],rt[i-1],1,n,fa[x],fa[y]);
if(dep[x]==dep[y]) add(rt[i],1,n,fa[y]);
}
if(op==2)
{
int u=read();
rt[i]=rt[u];
}
if(op==3)
{
rt[i]=rt[i-1];
int u=read(),v=read();
int x=find(rt[i],u),y=find(rt[i],v);
printf("%d\n",fa[x]==fa[y]);
}
}
}