主席树

发布时间 2023-10-30 21:41:48作者: Noname_min
//动态开点可持久化权值线段树
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; struct Segmentree { int ls,rs,sum; }t[N<<5]; int rt[N],tot=0,n,m,a[N],b[N],p;//p含义为修改点 void build(int p,int l,int r) { p=++tot; if(l==r) return; int mid=(l+r)>>1; build(t[p].ls,l,mid); build(t[p].rs,mid+1,r); } int update(int root,int l,int r) { int op=++tot; t[op].ls=t[root].ls,t[op].rs=t[root].rs,t[op].sum=t[root].sum+1; if(l==r) return op;//左端点等于右端点,可以结束了 int mid=(l+r)>>1; if(p<=mid) t[op].ls=update(t[op].ls,l,mid); else t[op].rs=update(t[op].rs,mid+1,r); return op; } long long query(int u,int v,int l,int r,int k) { long long ans=0;int mid=(l+r)>>1; int x=t[t[v].ls].sum-t[t[u].ls].sum; if(l==r) return l; if(x>=k) ans=query(t[u].ls,t[v].ls,l,mid,k); else ans=query(t[u].rs,t[v].rs,mid+1,r,k-x);//此处递归到右子树需要减掉左子树已经拥有的排名 return ans; } int main() { //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); int len=unique(b+1,b+n+1)-b-1;//离散化,sort unique build(rt[0],1,len);//建空树 for(int i=1;i<=n;i++) { p=lower_bound(b+1,b+1+len,a[i])-b; rt[i]=update(rt[i-1],1,len);//一个一个加上去 } for(int i=1;i<=m;i++) { int l,r,k; scanf("%d%d%d",&l,&r,&k); long long ans=query(rt[l-1],rt[r],1,len,k); //cout<<ans<<endl; printf("%d\n",b[ans]); } return 0; }

主席树 - 孤独·粲泽 - 博客园 (cnblogs.com)他写的太好