主席树区间求第k大的思路类似权值线段树树求[1,n]第k大。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int n,m,tot,rt[maxn];
int a[maxn],b[maxn],len; //离散化
struct node{int ls,rs,sum;}t[maxn<<5];//主席树
int getid(int val){return lower_bound(b+1,b+len+1,val)-b;}
int build(int l,int r){
int pos = ++tot;
if(l==r) return pos;
int mid = l+r>>1;
t[pos].ls = build(l,mid);
t[pos].rs = build(mid+1,r);
return pos;
}
int update(int rt,int l,int r,int pos){
int now = ++tot;
t[now] = t[rt] , t[now].sum++;
if(l==r) return now;
int mid = l+r>>1;
if(pos<=mid) t[now].ls = update(t[rt].ls,l,mid,pos);
else t[now].rs = update(t[rt].rs,mid+1,r,pos);
return now;
}
int query(int u,int v,int l,int r,int k){
if(l==r) return l;
int mid = l+r>>1 , p = t[t[u].ls].sum - t[t[v].ls].sum;//前缀和
if(k<=p) return query(t[u].ls,t[v].ls,l,mid,k);
else return query(t[u].rs,t[v].rs,mid+1,r,k-p);
}
int main(){
int _;
scanf("%d",&_);
while(_--){
tot = 0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]) , b[i] = a[i];
sort(b+1,b+n+1);
len = unique(b+1,b+n+1)-b-1; //离散化
rt[0] = build(1,len); //建立空树
for(int i=1;i<=n;i++)
rt[i] = update(rt[i-1],1,len,getid(a[i]));
while(m--){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",b[query(rt[r],rt[l-1],1,len,k)]);
}
}
return 0;
}