可持久化并查集

如果不采用路径压缩而只采用按秩合并,那么并查集的可持久化是比较容易实现的。按秩合并可以保证一棵 \(n\) 个节点的树的高度是 \(O(\log n)\) 的。

实现方法:
\(r_v\) 表示 \(v\) 所在子树的根。
假设要将点 \(u\) 和点 \(v\) 所在子树和并(也就是将边 \((u,v)\) 加入图中),那么需要在合并之前记录一下 \(r_u, \mathrm{rank}(r_u)\)\(r_v, \mathrm{rank}(r_v)\)
要恢复到某个历史版本,就按与加边相反的顺序删边。

const int N = 5e5 + 5;
int par[N];
int rk[N];

int root(int x){
	while(x != par[x]) x = par[x];
	return x;
}

struct his{
	int u, rk1;
	int v, rk2;
};

his unite(int x, int y){
	x = root(x);
	y = root(y);

	his res = {x, rk[x], y, rk[y]};

	if(x == y) return res;
	if(rk[x] > rk[y])
		par[y] = x;
	else{
		par[x] = y;
		if(rk[x] == rk[y])
			++rk[y];
	}
	return res;
}


void divide(const his &x){
	par[x.u] = x.u;
	par[x.v] = x.v;
	rk[x.u] = x.rk1;
	rk[x.v] = x.rk2;
}
posted @ 2017-11-18 13:37  Pat  阅读(179)  评论(0编辑  收藏  举报