n个数据建n个版本ver,每个版本里有一个线段树 且只有一条分支不同(即可通过继承得到部分)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,tot=0,ver[maxn];
//区间第k大/小的关键是按 值域(即题目给出的n个值)划分!若值是大数据或重复的就离散化
struct node{
int l,r,val;//val表示有多少个数在值域区间内
}tree[maxn<<5];//nlogn,logn~20,左移4位不够
//每个版本有一颗树,这颗树的每个节点都是一个树
int build(int l,int r){
int p=++tot;
tree[p].val=0;//初始为0,change时加
tree[p].l=p;tree[p].r=p;//ver0是个0树,而该树的每个节点都是一个线段树(的根节点也是0
return p;//根节点的值给ver
}
void pushup(int p){
tree[p].val=tree[tree[p].l].val+tree[tree[p].r].val;
}
int change(int rt,int l,int r,int pos){//pos在线段树中从小到大,方便找到第k大的数
//lr是值域
int p=++tot;
node &tt=tree[p];//tt指向新树,tt改变新树改变
tt=tree[rt];//继承
if(l==r){
tt.val++;
return p;
}
int mid=(l+r)/2;
if(pos<=mid) tt.l=change(tt.l,l,mid,pos);//新放入一个左树更新了,所以左子树的根改变
else tt.r=change(tt.r,mid+1,r,pos);
pushup(p);//改变或构造要pushup,本题构造的特殊可省去
return p;//根节点的值给ver
}
int ask(int per,int lst,int l,int r,int k){
if(l==r)return l;//l,r,mid,pos 值域
node &pp=tree[per],&ll=tree[lst];
int tx=tree[ll.l].val-tree[pp.l].val;//第几个,与k比较
//注意这里看两个版本的 左子树 的差,因为第k大要从左往右看
int mid=(l+r)>>1;//线段树里的位置
if(tx>=k) return ask(pp.l,ll.l,l,mid,k);
else return ask(pp.r,ll.r,mid+1,r,k-tx);
}
int main(){
int x,t,l,r,k;
cin>>t;
while(t--) {
scanf("%d%d",&n,&m);
tot=0;
ver[0]=build(1,n);
for(int i=1;i<=n;i++) {
scanf("%d",&x);
ver[i]=change(ver[i-1],1,n,x);
}
while(m--){
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",ask(ver[l-1],ver[r],1,n,k));
}
}
return 0;
}