bzoj3673&洛谷P3402 可持久化并查集【模板】

3673: 可持久化并查集 by zky

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 3535  Solved: 1619
[Submit][Status][Discuss]

Description

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

0<n,m<=2*10^4

Input

Output

Sample Input

5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2
 

Sample Output

1
0
1



 

HINT

Source

出题人大SB

题解:

本来以为可持久化并查集是什么高端操作,结果发现tm就是可持久化线段树维护并查集中的father数组,是个傻逼东西。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,f[2000001],dep[2000001],ls[2000001],rs[2000001],rt[2000001];
void build(int &x,int l,int r){
	x=++cnt;
	if(l==r){
		f[x]=l;
		return;
	}
	int mid=(l+r)/2;
	build(ls[x],l,mid);build(rs[x],mid+1,r);
}
void update(int &x,int la,int l,int r,int t,int k){
	x=++cnt;
	if(l==r){
		f[x]=k;
		dep[x]=dep[la];
		return;
	}
	int mid=(l+r)/2;
	ls[x]=ls[la];rs[x]=rs[la];
	if(mid>=t)update(ls[x],ls[la],l,mid,t,k);
	 else update(rs[x],rs[la],mid+1,r,t,k);
}
int query(int x,int l,int r,int t){
	if(l==r)return x;
	int mid=(l+r)/2;
	if(mid>=t)return query(ls[x],l,mid,t);
	 else return query(rs[x],mid+1,r,t);
}
void add(int x,int l,int r,int t){
	if(l==r){
		dep[x]++;
		return;
	}
	int mid=(l+r)/2;
	if(mid>=t)add(ls[x],l,mid,t);
	 else add(rs[x],mid+1,r,t);
}
int find(int now,int t){
	int x=query(now,1,n,t);
	if(t==f[x])return x;
	return find(now,f[x]);
}
int main(){
	int t1,t,k,x,y,i;
	scanf("%d%d",&n,&m);
	build(rt[0],1,n);
	for(i=1;i<=m;i++){
		scanf("%d%d",&t1,&t);
		if(t1==1){
			rt[i]=rt[i-1];
			scanf("%d",&k);
			x=find(rt[i],t);y=find(rt[i],k);
			if(f[x]==f[y])continue;
			if(dep[x]>dep[y])swap(x,y);
			update(rt[i],rt[i-1],1,n,f[x],f[y]);
			if(dep[x]==dep[y])add(rt[i],1,n,f[y]);
		}
		if(t1==2){
			rt[i]=rt[t];
		}
		if(t1==3){
			scanf("%d",&k);
			rt[i]=rt[i-1];
			x=find(rt[i],t);y=find(rt[i],k);
			if(f[x]==f[y])printf("1\n");
			 else printf("0\n");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/81126158