【模板】可持久化并查集

突然想起来大家都会的可持久化并查集我还不会,所以来学一下 q w q qwq qwq

感觉可持久化并查集就是把主席树上的点的存储信息改了一下。。
其他也没什么不同的,查询一个点的父亲的时候是 l o g 2 n log^2n log2n的,修改啥的都是 l o g n logn logn,总复杂度是 m l o g 2 n mlog^2n mlog2n,空间是 m l o g n mlogn mlogn

然而,,,看了一个dalao的博客之后觉得事情有那么一点点不同,这种写法好像很快的样子,但常数有点大比不过各位卡常选手

luogu模板题

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200005
#define M 7400005
using namespace std;

template<class T>inline void rd(T &x){
	x=0; short f=1; char c=getchar();
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	x*=f;
}

struct Data{
	int ls,rs,id,val,siz;
}node[M];
int root[N],tot,w[N];
int n,m,lt,nt,ans;

void build(int x){
	node[x].id=x,node[x].val=x,node[x].siz=1;
	int lson=x<<1;
	if(lson<=n){
		node[x].ls=lson;
		build(lson);
	}
	int rson=lson|1;
	if(rson<=n){
		node[x].rs=rson;
		build(rson);
	}
}

Data query(int cur,int L,int x){
	if(x==L) return node[cur];
	if(x&(1<<(w[x]-w[L]-1))) return query(node[cur].rs,L<<1|1,x);
	return query(node[cur].ls,L<<1,x);
}

inline Data find(int x){
	Data y=query(root[lt],1,x);
	while(y.id!=y.val) y=query(root[lt],1,y.val);
	return y;
}

void update(int cur,int L,int x,int tp,int v){
	if(L==x){
		if(tp==0) node[cur].val=v;
		else node[cur].siz=v;
		return;
	}
	if(x&(1<<(w[x]-w[L]-1))){
		Data tmp=node[node[cur].rs];
		node[cur].rs=++tot;
		node[tot]=tmp;
		update(node[cur].rs,L<<1|1,x,tp,v);
	}
	else {
		Data tmp=node[node[cur].ls];
		node[cur].ls=++tot;
		node[tot]=tmp;
		update(node[cur].ls,L<<1,x,tp,v);
	}
}

inline void add(int x,int y){
	Data fx=find(x),fy=find(y);
	if(fx.siz>fy.siz) swap(fx,fy);
	root[nt]=++tot;
	node[tot]=node[root[lt]];
	update(tot,1,fx.id,0,fy.id);
	//node[++tot]=node[root[nt]],root[nt]=tot; ?
	update(tot,1,fy.id,1,fx.siz+fy.siz);
}

int main(){
	rd(n); rd(m); int opt,x,y;
	build(1); root[1]=1; lt=nt=1; tot=n;
	w[1]=1; for(int i=2;i<N;i++) w[i]=w[i>>1]+1;
	while(m--){
		rd(opt);
		if(opt==1){
			rd(x),rd(y);
			nt++;
			add(x,y);
			lt=nt;
		}
		else if(opt==2){
			rd(x);
			nt++,lt=x+1;
			root[nt]=root[lt];
			lt=nt;
		}
		else{
			rd(x),rd(y);
			Data fx=find(x),fy=find(y);
			if(fx.val==fy.val) puts("1"),ans=1;
			else puts("0"),ans=0;
			nt++,root[nt]=root[lt];
			lt=nt;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值