可持久化并查集
思路:用可持久化线段树实现可持久化数组,然后并查集按秩合并即可。注意一些实现细节。
#include <cstdio>
#include <algorithm>
const int N=2e5+10;
int ch[N*30][2],dep[N*30],f[N*30],tot,n,m,root[N],T;
#define ls ch[now][0]
#define rs ch[now][1]
#define ols ch[las][0]
#define ors ch[las][1]
void build(int &now,int l,int r)
{
now=++tot;
if(l==r) {dep[now]=1,f[now]=l;return;}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
int query(int now,int l,int r,int p)
{
if(l==r) return now;
int mid=l+r>>1;
if(p<=mid) return query(ls,l,mid,p);
else return query(rs,mid+1,r,p);
}
void changef(int &now,int las,int l,int r,int p,int d)
{
if(!now) now=++tot;
if(l==r) {dep[now]=dep[las],f[now]=d;return;}
int mid=l+r>>1;
if(p<=mid) changef(ls,ols,l,mid,p,d),rs=ors;
else changef(rs,ors,mid+1,r,p,d),ls=ols;
}
void changed(int now,int l,int r,int p)
{
if(l==r) {++dep[now];return;}
int mid=l+r>>1;
if(p<=mid) changed(ls,l,mid,p);
else changed(rs,mid+1,r,p);
}
int Find(int x)
{
int fa=query(root[T],1,n,x);
if(f[fa]!=x) return Find(f[fa]);
return fa;
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("dew.out","w",stdout);
scanf("%d%d",&n,&m);
build(root[0],1,n);
for(int op,a,b,i=1;i<=m;i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&a,&b);
a=Find(a),b=Find(b);
++T;
if(a!=b)
{
if(dep[a]<dep[b]) std::swap(a,b);
changef(root[T],root[T-1],1,n,f[b],f[a]);
if(dep[a]==dep[b]) changed(root[T],1,n,f[a]);
}
else
root[T]=root[T-1];
}
else if(op==2)
scanf("%d",&a),root[++T]=root[a];
else
{
scanf("%d%d",&a,&b);
puts(Find(a)==Find(b)?"1":"0");
++T,root[T]=root[T-1];
}
}
return 0;
}
可持久化平衡树
思路:在写( ext{fhqtreap})的( ext{merge})和( ext{split})的时候每次新建节点进行可持久化,注意复制空节点的情况。空间要往大开,反正只乘个(log n)是不够的
#include <cstdio>
#include <cstdlib>
#define ls ch[now][0]
#define rs ch[now][1]
const int N=5e5+10;
const int inf=2147483647;
int ch[N*50][2],val[N*50],siz[N*50],dat[N*50],root[N],tot;
int Copy(int now)
{
if(!now) return 0;//注意
val[++tot]=val[now],siz[tot]=siz[now],dat[tot]=dat[now],ch[tot][0]=ls,ch[tot][1]=rs;
return tot;
}
void updata(int now){siz[now]=siz[ls]+siz[rs]+1;}
void split(int now,int k,int &x,int &y)
{
if(!now){x=y=0;return;}
if(k>=dat[now])
{
x=Copy(now);
split(ch[x][1],k,ch[x][1],y);
updata(x);
}
else
{
y=Copy(now);
split(ch[y][0],k,x,ch[y][0]);
updata(y);
}
}
int Merge(int x,int y)
{
if(!x||!y) return Copy(x+y);
int now;
if(val[x]<val[y])
now=Copy(x),rs=Merge(rs,y);
else
now=Copy(y),ls=Merge(x,ls);
return updata(now),now;
}
int New(int k)
{
dat[++tot]=k,siz[tot]=1,val[tot]=rand();
return tot;
}
void Insert(int id,int k)
{
int x,y;
split(root[id],k,x,y);
root[id]=Merge(x,Merge(New(k),y));
}
void extrack(int id,int k)
{
int x,y,z;
split(root[id],k,x,y);
split(x,k-1,x,z);
z=Merge(ch[z][0],ch[z][1]);
root[id]=Merge(x,Merge(z,y));
}
int Rank(int now,int k)//排名为k的数
{
if(k<=siz[ls]) return Rank(ls,k);
else if(k>siz[ls]+1) return Rank(rs,k-siz[ls]-1);
else return dat[now];
}
int frank(int now,int k)//查询k的排名
{
if(!now) return 1;
if(k<=dat[now]) return frank(ls,k);
else return frank(rs,k)+siz[ls]+1;
}
int main()
{
int m;scanf("%d",&m);
Insert(0,inf),Insert(0,-inf);
for(int v,op,x,i=1;i<=m;i++)
{
scanf("%d%d%d",&v,&op,&x);
root[i]=root[v];
if(op==1) Insert(i,x);
else if(op==2) extrack(i,x);
else if(op==3) printf("%d
",frank(root[i],x)-1);
else if(op==4) printf("%d
",Rank(root[i],x+1));
else if(op==5) printf("%d
",Rank(root[i],frank(root[i],x)-1));
else printf("%d
",Rank(root[i],frank(root[i],x+1)));
}
return 0;
}
2018.12.12