可持久化并查集
题意
如题。
解法
我们考虑用主席树来维护每一个版本中,x的father,因为我们要做到可持久化, 所以我们不能压缩路径(可能吧) ,我们就需要用到启发式合并。每次将深度较浅的合并到深度较大的集合中,并且,如果两个集合深度相同了的话,将其中的一个深度+1。剩下的就是主席树的基本操作了。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
x=0;T k=1;char c=getchar();
while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=1e5+5;
struct node{
int lc,rc,fa,deep;
}T[maxn*40];
int root[maxn*2],sz;
int n,m;
void build(int &x,int l,int r){
x=++sz;
if(l==r){
T[x].fa=l;
return;
}
int mid=(l+r)/2;
build(T[x].lc,l,mid);
build(T[x].rc,mid+1,r);
}
void update(int l,int r,int pos,int fa,int &x,int y){
T[++sz]=T[y],x=sz;
if(l==r) { T[x].fa=fa;return;}
int mid=(l+r)/2;
if(pos<=mid) update(l,mid,pos,fa,T[x].lc,T[y].lc);
else update(mid+1,r,pos,fa,T[x].rc,T[y].rc);
}
node query(int x,int l,int r,int pos){
if(l==r) return T[x];
int mid=(l+r)/2;
if(pos<=mid) return query(T[x].lc,l,mid,pos);
else return query(T[x].rc,mid+1,r,pos);
}
void add(int x,int l,int r,int pos){
if(l==r) { ++T[x].deep;return;}
int mid=(l+r)/2;
if(pos<=mid) add(T[x].lc,l,mid,pos);
else add(T[x].rc,mid+1,r,pos);
}
node find_fa(int x,int pos){
node k=query(x,1,n,pos);
if(k.fa==pos) return k;
return find_fa(x,k.fa);
}
void uni(int &x,int y,int pos1,int pos2){
x=y;
node f1=find_fa(x,pos1),f2=find_fa(x,pos2);
if(f1.fa!=f2.fa){
if(f1.deep>f2.deep) swap(f1,f2);
update(1,n,f1.fa,f2.fa,x,y);
if(f1.deep==f2.deep) add(x,1,n,f2.fa);
}
}
int main()
{
read(n),read(m);
build(root[0],1,n);
for(int i=1;i<=m;i++){
int k,x,y;
read(k);
if(k==1){
read(x),read(y);
uni(root[i],root[i-1],x,y);
}
if(k==2){
read(x);
root[i]=root[x];
}
if(k==3){
read(x),read(y);
root[i]=root[i-1];
node fa1=find_fa(root[i],x),fa2=find_fa(root[i],y);
if(fa1.fa==fa2.fa) printf("1
");
else printf("0
");
}
}
return 0;
}