【学习笔记】可持久化并查集(BZOJ3673)

好久之前就想学了 然后今天恰巧一道题需要用到就学了

前置芝士

1.主席树[可持久化数组]

2.并查集

如果你掌握了前面两个那么这个东西你就会觉得非常沙茶。。

 

构造

可持久化并查集 = 主席树  + 并查集

有点蠢= =

当然 我们这里的并查集是要按秩合并的并查集

[按秩合并:就是把dep小的连接到大的上面 这个复杂度分析出来是O(lgn)的 原因不要问我 我不知道= =]

不可以路径压缩 原因好像是可以被极限数据卡掉?[我也不知道路径压缩了你怎么访问历史版本的emm。。]

这样的话 我们每次开log个节点连下来 然后对于每个点维护fa和dep就可以了

然后dep的更新就是 当两个高度一样的时候 连起来那么被连的深度需要+1

就没了qwq。

例题就是BZOJ3673 真·模板

代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define mxn 200010
#define pa pair<int,int>
#define mp make_pair
using namespace std;

struct node{int ls,rs,fa,dep;}t[mxn*40];
int cnt,rt[mxn],n;
void build(int &x,int l,int r)
{
	x=++cnt;
	if(l==r){t[x].fa=l;t[x].dep=1;return;}
	int mid=l+r>>1;
	build(t[x].ls,l,mid); build(t[x].rs,mid+1,r);
}

void insert(int &x,int lt,int l,int r,int d,int fa)
{
	x=++cnt; t[x] = t[lt];
	if(l==r){t[x].fa = fa; return;}
	int mid = l+r>>1;
	if(d<=mid) insert(t[x].ls,t[lt].ls,l,mid,d,fa);
	else	insert(t[x].rs,t[lt].rs,mid+1,r,d,fa);
}

void update(int x,int l,int r,int d)
{
	if(l==r){t[x].dep++; return;}
	int mid = l+r>>1;
	if(d<=mid)	update(t[x].ls,l,mid,d);
	else	update(t[x].rs,mid+1,r,d);
}

int query(int x,int l,int r,int d)
{
	if(l==r)	return x;
	int mid = l+r>>1;
	if(d<=mid)	return query(t[x].ls,l,mid,d);
	else	return query(t[x].rs,mid+1,r,d);
}

int find(int root,int x)
{
	int pos = query(root,1,n,x);
	if(t[pos].fa==x)	return pos;
	return find(root,t[pos].fa);
}

int main()
{
	int m,opt,x,y;
	scanf("%d%d",&n,&m);
	build(rt[0],1,n);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&opt,&x);
		if(opt==2){rt[i]=rt[x];continue;}
		scanf("%d",&y); rt[i]=rt[i-1];
		int fx = find(rt[i],x),fy = find(rt[i],y);
		if(opt==1)
		{
			if(fx!=fy)
			{
				if(t[fx].dep < t[fy].dep)	swap(fx,fy);
				int ffx = t[fx].fa , ffy = t[fy].fa;
				insert(rt[i],rt[i-1],1,n,ffy,ffx);
				if(t[fx].dep == t[fy].dep)	update(rt[i],1,n,ffx);
			}
		}
		else	printf("%d\n",t[fx].fa==t[fy].fa);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值