浅谈可持续化并查集

窝太菜了只配浅谈呃呃呃

前置芝士

主席树& 并查集

主席树模板题

可持久化并查集 , 差不多可能大概应该就是在主席树上做并查集 , 用主席树维护每个点的父亲...

修改

每次新建一个节点

值得一提的是 , 如果用路径压缩会TM双LE2333 , 这里只能按秩合并 即每次把深度小的并查集合并到深度高的并查集中去(如果两个深度相同 , 则其中一个并查集深度++ ) 可以画图感性理解一下

查询

查询该点在当前版本中的位置

感觉讲的好苍白呃呃呃 , 还是直接看我的代码(垃圾堆)自行理解吧呃呃呃

#include <bits/stdc++.h>
using namespace std;
#define mid (l + r) / 2
const int N = 200005;

int n, m, cnt;
int deep[N * 30], f[N * 30]; // deep记录的是每个点的深度 , f记录的是父亲
int T[N * 30], L[N * 30], R[N * 30]; //这里试了几次....开N << 5就炸了(为什么是TLE) 30倍应该刚刚好

int build(int l, int r) {
	int rt = ++cnt;

	if(l == r) {
		f[rt] = l;
		return rt;
	}
	L[rt] = build(l, mid);
	R[rt] = build(mid + 1, r);
	return rt;
}
int updata(int pre, int l, int r, int ppx, int k) { // pre为上一个版本的当前节点(感性理解233) , ppx为待修改的位置, k为修改的值
	int rt = ++cnt;
	
	L[rt] = L[pre]; R[rt] = R[pre];
	if(l == r) {
		f[rt] = k; 
		deep[rt] = deep[pre]; // 别忘了继承这个深度
		return rt;
	}
	if(ppx <= mid) L[rt] = updata(L[pre], l, mid, ppx, k);
	else R[rt] = updata(R[pre], mid + 1, r, ppx, k);
	return rt;
}
int query(int u, int l, int r, int ppx) { // u为当前节点编号
	if(l == r) return u;
	if(ppx <= mid) return query(L[u], l, mid, ppx);
	else return query(R[u], mid + 1, r, ppx);
}
void add(int u, int l, int r, int ppx) {//增加当前并查集的深度
	if(l == r) {
		deep[u]++;
		return ;
	}
	if(l < r) {
		if(ppx <= mid) add(L[u], l, mid, ppx);
		else add(R[u], mid + 1, r, ppx);
	}
}
int find(int u, int x) {
	int fx = query(u, 1, n, x);
	if(x == f[fx]) return fx;
	return find(u, f[fx]);
}
int main() {
	ios :: sync_with_stdio(0);

	cin >> n >> m;
	T[0] = build(1, n);
	for(int i = 1; i <= m; i++) {
		int opt, a, b;
		cin >> opt;
		if(opt == 1) { 
			cin >> a >> b;
			T[i] = T[i - 1];
			int fa = find(T[i], a);
			int fb = find(T[i], b);
			if(f[fa] == f[fb]) continue;
			if(deep[fa] > deep[fb]) swap(fa, fb);
			T[i] = updata(T[i - 1], 1, n, f[fa], f[fb]);
			if(deep[fa] == deep[fb]) add(T[i], 1, n, f[fb]);
		}
		else if(opt == 2) {
			cin >> a;
			T[i] = T[a];
		}
		else {
			cin >> a >> b;
			T[i] = T[i - 1];
			if(f[find(T[i], a)] == f[find(T[i], b)]) cout << 1 << endl;
			else cout << 0 << endl;
		}
	}return 0;
}

有什么问题可以直接在评论区告诉窝的鹅鹅鹅

不会吧不会吧不会真有人看的叭

posted @ 2020-08-27 08:29  月夭  阅读(112)  评论(1编辑  收藏  举报