题目背景
这是个非常经典的主席树入门题——静态区间第K小
数据已经过加强,请使用主席树。同时请注意常数优化
题目描述
如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。
输入输出格式
输入格式:
第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。
第二行包含N个正整数,表示这个序列各项的数字。
接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第k小值。
输出格式:
输出包含k行,每行1个正整数,依次表示每一次查询的结果
输入输出样例
输入样例#1: 复制
5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
输出样例#1: 复制
6405
15770
26287
25957
26287
n,m<=2*10^5
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200010<<5;
int n,m,a[MAXN],rt[MAXN],sum[MAXN],b[MAXN];
int cnt,l[MAXN],r[MAXN];
inline int build(int L,int R){
int rt=++cnt;
if(L<R){
int mid=(L+R)>>1;
l[rt]=build(L,mid);
r[rt]=build(mid+1,R);
}
return rt;
}
inline int update(int pre,int L,int R,int c){
int rt=++cnt;
l[rt]=l[pre],r[rt]=r[pre],sum[rt]=sum[pre]+1;
if(L<R){
int mid=(L+R)>>1;
if(c<=mid) l[rt]=update(l[pre],L,mid,c);
else r[rt]=update(r[pre],mid+1,R,c);
}
return rt;
}
inline int query(int u,int v,int L,int R,int k){
if(L==R) return L;
int x=sum[l[v]]-sum[l[u]];
int mid=(L+R)>>1;
if(x>=k) return query(l[u],l[v],L,mid,k);
else return query(r[u],r[v],mid+1,R,k-x);
}
int main(){
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
int u=unique(b+1,b+1+n)-b-1;
rt[0]=build(1,u);
for(register int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+1+u,a[i])-b;
rt[i]=update(rt[i-1],1,u,a[i]);
}
while(m--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
printf("%d\n",b[query(rt[x-1],rt[y],1,u,z)]);
}
return 0;
}