BZOJ3674: 可持久化并查集加强版
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3674
用可持久化线段树维护可持久化数组,加上启发式合并,就成了可持久化并查集。。
用root数组来记录当前是第x次操作之后的情景,这样我们就可以返回某次操作之后了。
注意一直都是维护点的pos,画个图出来应该就比较清楚吧TAT
#include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r; i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 200500 using namespace std; int root[maxn],dep[maxn*21],fa[maxn*21],ls[maxn*21],rs[maxn*21]; int a,b,x,y,n,m,cnt,ans; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void build(int &i,int l,int r){ if (!i) i=++cnt; if (l==r){ fa[i]=l; return; } int mid=(l+r)/2; build(ls[i],l,mid); build(rs[i],mid+1,r); } int ask(int i,int l,int r,int val){ if (l==r) return i; int mid=(l+r)/2; if (val<=mid) return ask(ls[i],l,mid,val); else return ask(rs[i],mid+1,r,val); } int find(int i,int x){ int tmp=ask(i,1,n,x); if (fa[tmp]==x) return tmp; else return find(i,fa[tmp]); } void un(int l,int r,int x,int &y,int pos,int val){ y=++cnt; if (l==r) {fa[y]=val; dep[y]=dep[x];return;} int mid=(l+r)/2; ls[y]=ls[x],rs[y]=rs[x]; if (pos<=mid) un(l,mid,ls[x],ls[y],pos,val); else un(mid+1,r,rs[x],rs[y],pos,val); } void add(int i,int l,int r,int pos){ if (l==r) {dep[i]++; return;} int mid=(l+r)/2; if (pos<=mid) add(ls[i],l,mid,pos); else add(rs[i],mid+1,r,pos); } int main(){ n=read(); m=read(); build(root[0],1,n); rep(i,1,m){ int op=read(); if (op==1){ root[i]=root[i-1]; a=read()^ans; b=read()^ans; x=find(root[i],a); y=find(root[i],b); if (fa[x]==fa[y]) continue; if (dep[x]>dep[y]) swap(x,y); un(1,n,root[i-1],root[i],fa[x],fa[y]); if (dep[x]==dep[y]) add(root[i],1,n,fa[y]); } else if (op==2) { x=read()^ans; root[i]=root[x]; } else { root[i]=root[i-1]; a=read()^ans; b=read()^ans; x=find(root[i],a); y=find(root[i],b); if (fa[x]!=fa[y]) ans=0; else ans=1; printf("%d\n",ans); } } return 0; }