题目
题意:询问任意区间第k小数
#include<bits/stdc++.h>
using namespace std ;
const int N = 100010 ;
int n , m , sz , len , a[N] , b[N] , p;
int rt[N<<5] ;//记录第i棵权值线段树的根节点编号
int lc[N<<5] ; //记录每个结点的左子树编号
int rc[N<<5] ;
int sum[N<<5];//记录区间有多少个点值
void build(int &rt , int l , int r){
rt = sz++;
if(l == r) return ;
int mid = l + r >> 1 ;
build(lc[sz] , l , mid);
build(rc[sz] , mid + 1 , r);
}
int update(int rt , int l , int r){//依据前一棵树建造第当前这棵树,类似于前缀和
int ne = sz++;
lc[ne] = lc[rt] , rc[ne] = rc[rt] , sum[ne] = sum[rt] + 1 ;
if(l == r) return ne ;
int mid = l + r >> 1 ;
if(mid >= p){
lc[ne] = update(lc[rt] , l , mid);
}else{
rc[ne] = update(rc[rt] , mid + 1 , r);
}
return ne ;
}
int query(int u , int v , int l , int r , int k){
if(l == r) return l;
int mid = l + r >> 1 , x = sum[lc[v]] - sum[lc[u]] ;
if(x >= k){
return query(lc[u] , lc[v] , l , mid , k);
}else{
return query(rc[u] , rc[v] , mid + 1 , r , k-x);
}
}
int main(){
int n , m ;
scanf("%d%d" , &n , &m);
for(int i = 1 ; i <= n ; i++){
scanf("%d" , &a[i]);
b[i] = a[i];
}
sort(b + 1 , b + 1 + n);
len = unique(b + 1 , b + 1 + n) - b - 1 ;
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);
}
while(m--){
int l , r , k ;
scanf("%d%d%d" , &l , &r , &k);
printf("%d
" , b[query(rt[l-1] , rt[r] , 1 , len , k)]);
}
}