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
题解:
本来以为可持久化并查集是什么高端操作,结果发现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");
}
}
}