Description
Description: 自从zkysb出了可持久化并查集后…… hzwer:乱写能AC,暴力踩标程 KuribohG:我不路径压缩就过了! ndsf:暴力就可以轻松虐! zky:……
n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0 0<n,m<=2*10^5
用可持久化满二叉查找树实现可持久化数组,每次修改记录新的根
可持久化数组实现可持久化并查集
#include<cstdio> const int N=10000000; int ch[N][2]; int v[N],id[N]; int rts[200005],r; int p=262145,la=0; void build(int w,int s){ if(s){ build(w-s,s>>1); build(w+s,s>>1); ch[w][0]=w-s; ch[w][1]=w+s; } v[w]=id[w]=w; } int get(int w,int x){ while(id[w]!=x)w=ch[w][id[w]<x]; return v[w]; } int set(int w,int x,int y){ int u=p++; if(id[w]==x){ ch[u][0]=ch[w][0]; ch[u][1]=ch[w][1]; v[u]=y; }else{ bool d=id[w]<x; ch[u][d^1]=ch[w][d^1]; ch[u][d]=set(ch[w][d],x,y); v[u]=v[w]; } id[u]=id[w]; return u; } int find(int x){ int a=x,b; while((b=get(r,a))!=a)a=b; while((b=get(r,x))!=a)r=set(r,x,a),x=b; return a; } int n,m,o,a,b,c; int main(){ build(rts[0]=131072,65536); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ r=rts[i-1]; scanf("%d",&o); if(o==1){ scanf("%d%d",&a,&b); a=find(a^la); b=find(b^la); rts[i]=set(r,a,b); }else if(o==2){ scanf("%d",&a); rts[i]=rts[a^la]; }else{ scanf("%d%d",&a,&b); printf("%d\n",la=find(a^la)==find(b^la)); rts[i]=rts[i-1]; } } return 0; }