P3402 can persist and check template questions

Given the initial n sets, there is only one number i in each set at the beginning, and
then given m operations
1 ab represents the set where ab is merged
2 k represents the return to the second operation
3 ab represents the query whether the number ab belongs to the same set Yes output 1, No output 0

Obviously operation 2 shows that what we need to maintain is a persistent and searchable collection, because it needs to support the backtracking of historical versions. Since it is a union search, we know that the core of the common union query operation is the fa array, which is the parent node, so it can be persisted. The one that needs to be maintained is that our fa array can be persisted.

And there are two common optimization methods that we commonly use in the merge search. One is path compression, and the other is merging by rank (that is, merging according to the number height to the larger one), which reduces the height of the tree as a whole to achieve the optimization effect. However, the first type of optimized path compression will generate huge space consumption (it seems to be) in a durable structure, so we can only use the second type of path compression to optimize. So we need to maintain another persistent array dep array, which represents the high of the union search

For the rest of the specific implementation, please
refer to the code for reference, and the explanation video is quite clear.

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 2e5+7;
//可持久化 并查集 经典模板题
//1 a b 合并ab所在的集合 并查集的操作
//2 k 回到第k次操作由此可以想到 用一个 可持久化数组 维护一下节点
//3 a b 询问ab是否在同一个区间 并查集的询问操作
//用主席数维护一个fa和一个dep数组
//merge有两种写法 一种是 merge里面带判断 另一种先判断秩的关系 在merge

int dep[MAXN],fa[MAXN],n,size,m;//dep和fa这两个数组时用来可持久化维护的 相当于记录不同功能的不同版本
struct HJT_tree
{
    
    
	int l,r,sum;//这个sum 一部分是记录fa数组的祖先节点的值 另一部分是记录dep数组的值 用到哪个时候调用相应的内存池即可
}tree[MAXN*40*2];
//可持久化数组操作
void build(int &now,int l,int r)//需要对now进行修改的时候 再传引用即(&now)
{
    
    
	now = ++size;
	if(l == r){
    
    
		tree[now].sum = l;//dep初始化都是0
		return ;
	}
	int mid = (l+r)>>1;
	build(tree[now].l,l,mid);
	build(tree[now].r,mid+1,r);
}

void update(int l,int r,int pre,int &now,int pos,int val)
{
    
    
	now = ++size;
	tree[now] = tree[pre];
	if(l == r){
    
    
		tree[now].sum = val;
		return ;
	}
	int mid = (l+r)>>1;
	if(pos <= mid) update(l,mid,tree[pre].l,tree[now].l,pos,val);
	else update(mid+1,r,tree[pre].r,tree[now].r,pos,val);
}

int query(int now,int l,int r,int pos)
{
    
    
	if(l == r) return tree[now].sum;
	int mid = (l+r)>>1;
	if(pos <= mid) return query(tree[now].l,l,mid,pos);
	else return query(tree[now].r,mid+1,r,pos);
}
//以上是树的操作

//并查集的相关操作
int Find(int now,int x)
{
    
    
	int fx = query(fa[now],1,n,x);
	return fx == x ? x : Find(now,fx);//注意这里不要路径压缩
}

void merge(int now,int x,int y)
{
    
    
	int fx = Find(now-1,x),fy = Find(now-1,y);//这里是前一个版本的操作 因为新的版本还没生成 (也可以在主函数里传前一个版的参数)
	if(fx == fy){
    
    
		fa[now] = fa[now-1];
		dep[now] = dep[now-1];
		return ;
	}
	else{
    
    //注意后面的操作都是对fx和fy操作 合并修改的时候都是既要改深度也要改高度
		int depx = query(dep[now-1],1,n,fx);
		int depy = query(dep[now-1],1,n,fy);
		if(depx != depy){
    
    //这里 高度不一样的话 把小的连接到大的上面来完成
			if(depx > depy) swap(fx,fy);
			update(1,n,fa[now-1],fa[now],fx,fy);
			dep[now] = dep[now-1];
		}
		if(depx == depy){
    
    
			update(1,n,fa[now-1],fa[now],fx,fy);
			update(1,n,dep[now-1],dep[now],fy,depy+1);
		}
	}
}
//以上是并查集的相关操作

int main()
{
    
    
	scanf("%d%d",&n,&m);
	build(fa[0],1,n);//这类dep初始化都看成0即可 所以不需要 我们构建
	for(int v = 1;v <= m;v ++){
    
    
		int op,a,b,k;
		scanf("%d",&op);
		switch(op){
    
    
			case 1:
				scanf("%d%d",&a,&b);
				merge(v,a,b);
				break;
			case 2:
				scanf("%d",&k);
				fa[v] = fa[k];//回溯状态
				dep[v] = dep[k];
				break; 
			case 3:
				scanf("%d%d",&a,&b);
				fa[v] = fa[v-1];//产生新状态
				dep[v] = dep[v-1];
				int fa = Find(v,a),fb = Find(v,b);
				printf(fa == fb?"1\n":"0\n");
				break;
		}
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/108486779