可持久化数组
题意:如题,你需要维护这样的一个长度为N的数组,支持如下几种操作:
1 在某个历史版本上修改某一个位置上的值
2 访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本.版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组).
const int N=1e6+5;
int tot,a[N],root[N];
struct ZXS{
int ls[N*30],rs[N*30],val[N*30];
inline int build(int l,int r){
int i=++tot;
if(l==r){val[i]=a[l];return i;}
int mid=(l+r)>>1;
ls[i]=build(l,mid);rs[i]=build(mid+1,r);
return i;
}
inline int change(int p,int l,int r,int x,int d){
int i=++tot;
if(l==r){val[i]=d;return i;}
ls[i]=ls[p];rs[i]=rs[p];
int mid=(l+r)>>1;
if(x<=mid)ls[i]=change(ls[p],l,mid,x,d);
else rs[i]=change(rs[p],mid+1,r,x,d);
return i;
}
inline int ask(int p,int l,int r,int x){
if(l==r)return val[p];
int mid=(l+r)>>1;
if(x<=mid)return ask(ls[p],l,mid,x);
else return ask(rs[p],mid+1,r,x);
}
}T;
int main(){
int n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
root[0]=T.build(1,n);
for(int i=1;i<=m;i++){
int id=read(),opt=read(),pos=read();
if(opt==1)root[i]=T.change(root[id],1,n,pos,read());
else root[i]=root[id],printf("%d
",T.ask(root[id],1,n,pos));
}
return 0;
}
可持久化线段树(主席树)
题意:给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值.
const int N=2e5+5;
int tot,root[N],b[N];
struct ppx{
int val,id;
inline bool operator <(ppx x){return val<x.val;}
}a[N];
struct PPX{
int ls[N*30],rs[N*30],data[N*30];
inline int build(int l,int r){
int i=++tot;
if(l==r)return i;
int mid=(l+r)>>1;
ls[i]=build(l,mid);rs[i]=build(mid+1,r);
return i;
}
inline int add(int p,int l,int r,int x,int d){
int i=++tot;ls[i]=ls[p];rs[i]=rs[p];
if(l==r){data[i]+=d;return i;}
int mid=(l+r)>>1;
if(x<=mid)ls[i]=add(ls[p],l,mid,x,d);
else rs[i]=add(rs[p],mid+1,r,x,d);
data[i]=data[ls[i]]+data[rs[i]];
return i;
}
inline int ask(int i,int j,int l,int r,int k){
if(l==r)return a[l].val;
int mid=(l+r)>>1,num=data[ls[j]]-data[ls[i]];
if(k<=num)return ask(ls[i],ls[j],l,mid,k);
else return ask(rs[i],rs[j],mid+1,r,k-num);
}
}T;
int main(){
int n=read(),m=read();
for(int i=1;i<=n;i++)a[i].val=read(),a[i].id=i;
sort(a+1,a+n+1);for(int i=1;i<=n;i++)b[a[i].id]=i;
root[0]=T.build(1,n);
for(int i=1;i<=n;i++)root[i]=T.add(root[i-1],1,n,b[i],1);
for(int i=1;i<=m;i++){
int l=read()-1,r=read(),k=read();
printf("%d
",T.ask(root[l],root[r],1,n,k));
}
return 0;
}
可持久化并查集
题意:n个集合,m个操作.
操作1:合并a,b所在集合;
操作2:回到第k次操作之后的状态(查询也算作操作);
操作3:询问a,b是否属于同一集合;
const int N=200005;
int n,m,tot,root[N];
struct ppx{
int ls[N*30],rs[N*30],deep[N*30],fa[N*30];
inline int build(int l,int r){
int i=++tot;
if(l==r){fa[i]=l;deep[i]=1;return i;}
int mid=(l+r)>>1;
ls[i]=build(l,mid);rs[i]=build(mid+1,r);
return i;
}
inline int add(int p,int l,int r,int x,int d){
int i=++tot;
if(l==r){fa[i]=d;return i;}
int mid=(l+r)>>1;ls[i]=ls[p];rs[i]=rs[p];
if(x<=mid)ls[i]=add(ls[p],l,mid,x,d);
else rs[i]=add(rs[p],mid+1,r,x,d);
return i;
}
inline int ask(int p,int l,int r,int x){
if(l==r)return p;
int mid=(l+r)>>1;
if(x<=mid)return ask(ls[p],l,mid,x);
else return ask(rs[p],mid+1,r,x);
}
inline int get(int p,int x){
int ff=ask(p,1,n,x);
if(x==fa[ff])return ff;
return get(p,fa[ff]);
}
}T;
int main(){
n=read(),m=read();
root[0]=T.build(1,n);
for(int i=1;i<=m;i++){
int opt=read();
if(opt==1){
int x=T.get(root[i-1],read());
int y=T.get(root[i-1],read());
if(T.deep[x]>=T.deep[y]){
T.deep[x]=max(T.deep[x],T.deep[y]+1);
root[i]=T.add(root[i-1],1,n,T.fa[y],T.fa[x]);
}
else root[i]=T.add(root[i-1],1,n,T.fa[x],T.fa[y]);
}
else if(opt==2)root[i]=root[read()];
else{
root[i]=root[i-1];
int x=T.fa[T.get(root[i-1],read())];
int y=T.fa[T.get(root[i-1],read())];
printf("%d
",x==y);
}
}
return 0;
}