可持久化并查集

solution

可持久化数据结构是在原数据结构的基础上增加维护历史版本的功能。但可持久化并查集的具体思路是利用主席树维护不同版本的每个节点的父节点.如果并查集结构是链式,用按秩合并会导致单次查询复杂度为\(n\log n\),于是我们可以启发式合并,将最大深度较小的集合合并到较大的那一个.剩下的,暴力查询暴力合并即可.由于我不想(会)打启发式合并,于是写了手随机化,平均复杂度O(nlog^n),可以通过所有数据.

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
#include<ctime>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define mod 31011
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> inline void read(T &x);
template <typename T> inline void write(T x);
template <typename T> inline void writesp(T x);
template <typename T> inline void writeln(T x);
const ll N=1e5+5, M=2e5+5;

ll n, m;
ll rt[M];

namespace seg{
	ll lc[M<<5], rc[M<<5], f[M<<5], d[M<<5], cnt;
	
	inline void build(ll &p, ll l, ll r){
		if(!p) p=++cnt;
		if(l==r) return (void) (f[p]=l, d[p]=rand());
		ll mid=l+r>>1;
		build(lc[p], l, mid);build(rc[p], mid+1, r);
	}
	
	inline ll getf(ll p, ll l, ll r, ll k, ll &d, ll ffa){
		if(l==r){
			++d;
			if(f[p]==l) return l;
			return getf(ffa, 1, n, f[p], d, ffa);
		}
		ll mid=l+r>>1;
		if(k<=mid) return getf(lc[p], l, mid, k, d, ffa);
		else return getf(rc[p], mid+1, r, k, d, ffa);
	}
	
	inline void update(ll &p, ll fa, ll l, ll r, ll k, ll ffa){
		p=++cnt;
		lc[p]=lc[fa], rc[p]=rc[fa];
		if(l==r) return (void) (f[p]=ffa, d[p]=rand()*rand());
		ll mid=l+r>>1;
		if(k<=mid) update(lc[p], lc[fa], l, mid, k, ffa);
		else update(rc[p], rc[fa], mid+1, r, k, ffa);
	}
	
	inline ll get(ll p, ll l, ll r, ll k){
		if(l==r) return p;
		ll mid=l+r>>1;
		if(k<=mid) return get(lc[p], l, mid, k);
		else return get(rc[p], mid+1, r, k);
	}
	
	inline void merge(ll k, ll x, ll y){
		ll dx=0,dy=0;
		ll fx=getf(rt[k-1], 1, n, x, dx, rt[k-1]), fy=getf(rt[k-1], 1, n, y, dy, rt[k-1]);
		if(fx==fy) return (void) (rt[k]=rt[k-1]);
		if(d[get(rt[k-1], 1, n, fx)]>d[get(rt[k-1], 1, n, fy)]) swap(fx, fy);
		update(rt[k], rt[k-1], 1, n, fx, fy);
	}
	
	inline void check(ll k,ll x,ll y){
		rt[k]=rt[k-1];
		ll dx=0;
		writeln(getf(rt[k], 1, n, x, dx, rt[k])==getf(rt[k], 1, n, y, dx, rt[k]));
	}
}
ll nouse;
int main(){
//	freopen("P3402_5.in", "r", stdin);
//	freopen("wn.out", "w", stdout);
	srand(time(0)); srand(rand());
	read(n); read(m);
	seg::build(rt[0],1,n);
	for(R ll i=1, op, x, y, k; i<=m; i++){
		read(op);
		if(op==2){
			read(k);
			rt[i]=rt[k];
		}
		else{
			read(x);read(y);
			if(op==1){
				seg::merge(i, x, y);
			}
			else{
				seg::check(i, x, y);
			}
		}
	}
}

template <typename T> inline void read(T &x){
	x=0; T t=1;
	char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') t=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=t;
}

template <typename T> inline void write(T x){
	if(x<0){putchar('-'); x=-x;}
	if(x<=9){putchar(x+'0'); return;}
	write(x/10); putchar(x%10+'0');
}

template <typename T> inline void writesp(T x){
	write(x); putchar(' ');
}

template <typename T> inline void writeln(T x){
	write(x); putchar('\n');
}
posted @ 2020-08-20 16:36  月落乌啼算钱  阅读(110)  评论(0编辑  收藏  举报