主席树/可持久化线段树/数组
int idx; //目前一共建立过多少节点 int sum[N<<2],ls[N<<2],rs[N<<2]; int root[N]; //每次修改对应的根节点编号 //建立空树 void build(int &k,int l,int r){ k=++idx; if(l==r) return; int mid=(l+r)>>1; build(ls[k],l,mid); build(rs[k],mid+1,r); } //修改操作 void change(int kp,int &k,int l,int r,int p,int d){ k=++idx; ls[k]=ls[kp],rs[k]=rs[kp]; sum[k]=sum[kp]+d; if(l==r) return; int mid=(l+r)>>1; if(p<=mid) change(ls[k],ls[k],l,mid,p,d); else change(rs[k],rs[k],mid+1,r,p,d); } //区间和查询 int query(int k,int l,int r,int x,int y){ if(x<=l&&r<=y) return sum[k]; int mid=(l+r)>>1,ans=0; if(x<=mid) ans+=query(ls[k],l,mid,x,y); if(mid<y) ans+=query(rs[k],mid+1,r,x,y); return ans; } //可持久化线段树注意事项: //1.取地址 //2.先建点,后if(l==r)return //3.空间开(n+Qlogn)
主席树操作模板
例题:1.可持久化线段树1(主席树) luogu模板 3834 静态区间第k大
利用主席树构建前缀树,将数据离散化后按照大小放入前缀树中,最后查找x-1和y两棵树内情况找到第k大的编号,最后根据离散化后的数组输出真实值
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) #define dec(i,x,y) for(register int i=x;i>=y;i--) #define ll long long using namespace std; const int N=200050; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} namespace zjc{ int n,m,q,idx,a[N],b[N],root[N]; int ls[N<<5],rs[N<<5],sum[N<<5]; inline void build(int &k,int l,int r){ k=++idx; if(l==r) return; int mid=(l+r)>>1; build(ls[k],l,mid); build(rs[k],mid+1,r); } inline void change(int &k,int kp,int l,int r,int p){ k=++idx; ls[k]=ls[kp],rs[k]=rs[kp],sum[k]=sum[kp]+1; if(l==r) return; int mid=(l+r)>>1; if(p<=mid) change(ls[k],ls[kp],l,mid,p); else change(rs[k],rs[kp],mid+1,r,p); } inline int query(int x,int y,int l,int r,int k){ if(l==r) return l; int mid=(l+r)>>1,s=sum[ls[y]]-sum[ls[x]]; if(k<=s) return query(ls[x],ls[y],l,mid,k); else return query(rs[x],rs[y],mid+1,r,k-s); } inline int find(int x){ return lower_bound(b+1,b+1+m,x)-b;} void work(){ n=read(),q=read(); rep(i,1,n) a[i]=read(),b[i]=a[i]; sort(b+1,b+1+n); m=unique(b+1,b+1+n)-(b+1); build(root[0],1,m); rep(i,1,n) change(root[i],root[i-1],1,m,find(a[i])); while(q--){ int x,y,z; x=read(),y=read(),z=read(); int t=query(root[x-1],root[y],1,m,z); printf("%d\n",b[t]); } return; } } int main(){ zjc::work(); return 0; }
2.可持久化数组 luogu 模板3919 回到历史版本
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) #define ll long long using namespace std; const int N=1000050; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} namespace zjc{ int n,m,idx,a[N],root[N<<5]; int ls[N<<5],rs[N<<5],mx[N<<5]; int v,k,p,val,s; inline void build(int &k,int l,int r){ k=++idx; if(l==r){mx[k]=a[l];return;} int mid=(l+r)>>1; build(ls[k],l,mid);build(rs[k],mid+1,r); } inline void change(int &k,int kp,int l,int r,int p,int d){ k=++idx;ls[k]=ls[kp],rs[k]=rs[kp],mx[k]=mx[kp]; if(l==r) {mx[k]=d;return;} int mid=(l+r)>>1; if(p<=mid) change(ls[k],ls[kp],l,mid,p,d); else change(rs[k],rs[kp],mid+1,r,p,d); } inline int query(int k,int l,int r,int p){ if(l==r) return mx[k]; int mid=(l+r)>>1; if(p<=mid) return query(ls[k],l,mid,p); else return query(rs[k],mid+1,r,p); } void work(){ n=read(),m=read(); rep(i,1,n) a[i]=read(); build(root[0],1,n); rep(i,1,m){ int pre=read(),opt=read(),p=read(); if(opt==1){int v=read();change(root[i],root[pre],1,n,p,v);} if(opt==2){printf("%d\n",query(root[pre],1,n,p));root[i]=root[pre];}} return; } } int main(){ zjc::work(); return 0; }
3.可持久化平衡树
以后填坑吧,splay treap都不咋会