bzoj 3674 可持久化并查集加强版——可持久化并查集
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3674
用主席树维护 fa[ ] 和 siz[ ] 。改 fa[ ] 和改 siz[ ] 都是新建节点。
写成 rt[ i ] = rt[ i-1 ] ,因为跳到第 k 步之后的那个第 k 步不一定是一个 0 操作。
找 fa 就是在当前版本的主席树查很多次。可以路径压缩,就和改 fa[ ] 一样,覆盖当前版本。不过空间会很大(n*50都不行,n*70可以),而且还变慢了?
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } const int N=2e5+5,M=N*70; int n,m,rt[N],ans; int tot,ls[M],rs[M],vl[M],siz[M]; void build(int l,int r,int cr) { if(l==r){vl[cr]=l;siz[cr]=1;return;} int mid=l+r>>1; ls[cr]=++tot; build(l,mid,ls[cr]); rs[cr]=++tot; build(mid+1,r,rs[cr]); } void ins(int l,int r,int &cr,int pr,int p,int k) { cr=++tot;ls[cr]=ls[pr];rs[cr]=rs[pr]; if(l==r){vl[cr]=k;siz[cr]=siz[pr];return;} int mid=l+r>>1; if(p<=mid)ins(l,mid,ls[cr],ls[pr],p,k); else ins(mid+1,r,rs[cr],rs[pr],p,k); } void add(int l,int r,int &cr,int pr,int p,int k) { cr=++tot;ls[cr]=ls[pr];rs[cr]=rs[pr]; if(l==r){vl[cr]=vl[pr];siz[cr]=siz[pr]+k;return;} int mid=l+r>>1; if(p<=mid)add(l,mid,ls[cr],ls[pr],p,k); else add(mid+1,r,rs[cr],rs[pr],p,k); } int qry(int l,int r,int cr,int p) { if(l==r)return cr; int mid=l+r>>1;//return cr not vl for qry siz if(p<=mid)return qry(l,mid,ls[cr],p); else return qry(mid+1,r,rs[cr],p); } int fnd(int nw,int a) { int fa=qry(1,n,nw,a); if(a==vl[fa])return fa; fa=fnd(nw,vl[fa]); ins(1,n,nw,nw,a,vl[fa]);//fa[a]=fnd(fa[a]) return fa; } int main() { n=rdn();m=rdn(); rt[0]=tot=1;build(1,n,rt[0]); for(int i=1,op,u,v;i<=m;i++) { op=rdn(); if(op==1) { rt[i]=rt[i-1]; u=rdn();v=rdn(); u=fnd(rt[i],u^ans); v=fnd(rt[i],v^ans); if(vl[u]==vl[v])continue; if(siz[u]>siz[v])swap(u,v); u=vl[u];v=vl[v]; ins(1,n,rt[i],rt[i],u,v); add(1,n,rt[i],rt[i],v,siz[u]); } else if(op==2){ u=rdn()^ans; rt[i]=rt[u];} else { rt[i]=rt[i-1]; u=rdn();v=rdn(); u=vl[fnd(rt[i],u^ans)]; v=vl[fnd(rt[i],v^ans)]; ans=(u==v); printf("%d\n",ans); } } return 0; }