传送门
可持久化并查集,实际上就是用可持久化线段树维护一下每一个点的father。这道题我加了路径压缩,这样的话感觉不是很科学,因为最坏情况下应该是 log2 的。
据说这道题应该用按秩合并?
#include
#include
#include
using namespace std;
#define N 200005
int n,m,opt,a,b,k,sz,ans;
int root[N];
int val[N*100],ls[N*100],rs[N*100];
void build(int &now,int l,int r)
{
int mid=(l+r)>>1;
ls[++sz]=ls[now],rs[sz]=rs[now];now=sz;
if (l==r)
{
val[now]=l;
return;
}
build(ls[now],l,mid);
build(rs[now],mid+1,r);
}
void change(int &now,int l,int r,int x,int v)
{
int mid=(l+r)>>1;
ls[++sz]=ls[now],rs[sz]=rs[now];now=sz;
if (l==r)
{
val[now]=v;
return;
}
if (x<=mid) change(ls[now],l,mid,x,v);
else change(rs[now],mid+1,r,x,v);
}
int query(int now,int l,int r,int x)
{
int mid=(l+r)>>1;
if (l==r) return val[now];
if (x<=mid) return query(ls[now],l,mid,x);
else return query(rs[now],mid+1,r,x);
}
int find(int x,int rt)
{
int fa=query(root[rt],1,n,x);
if (fa==x) return x;
int faa=find(fa,rt);
change(root[rt],1,n,x,faa);
return faa;
}
int main()
{
scanf("%d%d",&n,&m);
build(root[0],1,n);
for (int i=1;i<=m;++i)
{
scanf("%d",&opt);
root[i]=root[i-1];
if (opt==1)
{
scanf("%d%d",&a,&b);
a^=ans,b^=ans;
int f1=find(a,i),f2=find(b,i);
if (f1!=f2) change(root[i],1,n,f1,f2);
}
if (opt==2)
{
scanf("%d",&k);
k^=ans;
root[i]=root[k];
}
if (opt==3)
{
scanf("%d%d",&a,&b);
a^=ans,b^=ans;
if (find(a,i)==find(b,i)) puts("1"),ans=1;
else puts("0"),ans=0;
}
}
}