题意:
多组案例。
给n和m,表示长度为n的数列,和m个询问
每个询问要求输出区间L-R中第K小的数
分析:
区间第K小模板题,
直接上主席树
要用到离散化
ps:
据说主席树空间要开40倍
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxm=1e5+5;
struct Node{
int lc,rc,cnt;
}a[maxm*40];
int r[maxm],cnt;
int b[maxm],xx[maxm];
void init(){
cnt=0;
}
void pushup(int k){
a[k].cnt=a[a[k].lc].cnt+a[a[k].rc].cnt;
}
int build(int l,int r){
int k=cnt++;
a[k].cnt=0;
if(l!=r){//非叶节点继续递归
int mid=(l+r)/2;
a[k].lc=build(l,mid);
a[k].rc=build(mid+1,r);
}
return k;
}
int update(int x,int val,int l,int r,int last){
int k=cnt++;
a[k]=a[last];//复制lc和rc和cnt(lc和rc有一边是不用修改的)
if(l==r){
a[k].cnt+=val;
return k;
}
int mid=(l+r)/2;
if(x<=mid)a[k].lc=update(x,val,l,mid,a[last].lc);
else a[k].rc=update(x,val,mid+1,r,a[last].rc);
pushup(k);
return k;
}
int ask(int k,int l,int r,int x,int y){
if(l==r)return l;
int mid=(l+r)/2;
int res=a[a[y].lc].cnt-a[a[x].lc].cnt;
if(k<=res)return ask(k,l,mid,a[x].lc,a[y].lc);//和权值线段树求第k小一样
return ask(k-res,mid+1,r,a[x].rc,a[y].rc);
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
xx[i]=b[i];
}
sort(xx+1,xx+1+n);
int num=unique(xx+1,xx+1+n)-xx-1;
r[0]=build(1,num);
for(int i=1;i<=n;i++){
int p=lower_bound(xx+1,xx+1+num,b[i])-xx;
r[i]=update(p,1,1,num,r[i-1]);
}
for(int i=1;i<=m;i++){
int a,b,k;
scanf("%d%d%d",&a,&b,&k);
int idx=ask(k,1,num,r[a-1],r[b]);
printf("%d\n",xx[idx]);
}
}
return 0;
}