主席树,又称可持久化线段树,又称函数式线段树。
主席树空间复杂度ο((N+MlogN)
树的大小要开MlogN(改一次logN)
注意点:1.树的大小
2.多是维护权值,要离散化
3.难以支持大部分“区间修改”
4.在代码中
p3834
#include<bits/stdc++.h>
using namespace std; const int N=2e5+7; struct tree{ int ch[2],dat; }T[5000007]; int tot,root[N],n,a[N],m,b[N],t; void update(int p){ T[p].dat=T[T[p].ch[0]].dat+T[T[p].ch[1]].dat; return; } int build(int l,int r){//其实这题不用build... int p=++tot; if(l==r){ T[p].dat=a[l]; return p; } int mid=(l+r)>>1; T[p].ch[0]=build(l,mid); T[p].ch[1]=build(mid+1,r); update(p); return p; } int insert(int now,int l,int r,int x,int val){ int p=++tot; T[p]=T[now]; if(l==r){ T[p].dat+=val; return p; } int mid=(l+r)>>1; if(x<=mid) T[p].ch[0]=insert(T[p].ch[0],l,mid,x,val); else T[p].ch[1]=insert(T[p].ch[1],mid+1,r,x,val); update(p); return p; } int ask(int p,int q,int l,int r,int k){ if(l==r)return l; int mid=(l+r)>>1; int lcnt=T[T[p].ch[0]].dat-T[T[q].ch[0]].dat; if(k<=lcnt)return ask(T[p].ch[0],T[q].ch[0],l,mid,k); else return ask(T[p].ch[1],T[q].ch[1],mid+1,r,k-lcnt); } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); t=unique(b+1,b+1+n)-(b+1); for(int i=1;i<=n;i++){//离散化 int x=lower_bound(b+1,b+t+1,a[i])-b; root[i]=insert(root[i-1],1,t,x,1); } for(int i=1;i<=m;i++){ int x,y,k; scanf("%d%d%d",&x,&y,&k); printf("%d\n",b[ask(root[y],root[x-1],1,t,k)]); } return 0; }
原文:https://www.cnblogs.com/Hikigaya/p/10589297.html