可持久化并查集

可持久化并查集

题意

如题。

解法

我们考虑用主席树来维护每一个版本中,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;
}