可持久化并查集备忘

luogu 3402

主要要理解深度的变化,因为是把深度较小的并查集合并到深度较大的上(这里的深度指的是并查集内最深的一个点的深度),所以只有当两个并查集深度相同的时候,较大的并查集的深度才会发生改变.

注意没有路径压缩,然后主要的是主席树维护每个时刻并查集的fa数组

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,m,rt[maxn],cnt;
struct node{
	int fa,dep,l,r;
}t[maxn*40];
void build(int &rt,int l,int r){
	rt=++cnt;
	if(l==r){t[rt].fa=l;t[rt].dep=1;return ;}
	int mid=l+r>>1;
	build(t[rt].l,l,mid);build(t[rt].r,mid+1,r);
}
void update(int &rt,int pre,int l,int r,int x,int fa){
	rt=++cnt;
	t[rt].l=t[pre].l;
	t[rt].r=t[pre].r;
	if(l==r){t[rt].fa=fa;t[rt].dep=t[pre].dep;return ;}
	int mid=l+r>>1;
	if(x<=mid)update(t[rt].l,t[pre].l,l,mid,x,fa);
	else update(t[rt].r,t[pre].r,mid+1,r,x,fa);
}
int query(int rt,int l,int r,int x){
	if(l==r)return rt;
	int mid=l+r>>1;
	if(x<=mid)return query(t[rt].l,l,mid,x);
	else return query(t[rt].r,mid+1,r,x);
}
int find(int a,int x){
	int f=query(rt[a],1,n,x);
	if(t[f].fa==x)return f;
	else return find(a,t[f].fa);
}
void add(int rt,int l,int r,int x){
	if(l==r){t[rt].dep++;return ;}
	int mid=l+r>>1;
	if(x<=mid)add(t[rt].l,l,mid,x);
	else add(t[rt].r,mid+1,r,x);
}
int main(){
	n=read(),m=read();
	build(rt[0],1,n);
	int opt,a,b,i;
	while(m--){i++;
		opt=read();
		if(opt==1){
			rt[i]=rt[i-1];
			a=read(),b=read();
			int fa=find(i-1,a),fb=find(i-1,b);
			if(t[fa].fa==t[fb].fa)continue;
			if(t[fa].dep<t[fb].dep)swap(fa,fb);
			update(rt[i],rt[i-1],1,n,t[fb].fa,t[fa].fa);
			if(t[fb].dep==t[fa].dep)add(rt[i],1,n,t[fa].fa)//由于是深度小的合到深度大的上,所以把深度大的增加深度
		}
		else if(opt==2){
			a=read();
			rt[i]=rt[a];
		}
		else{
			rt[i]=rt[i-1];
			a=read(),b=read();
			int fa=find(i,a),fb=find(i,b);
			printf("%d\n",t[fa].fa==t[fb].fa);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值