函数式线段树。
利用了可持久化的思想,降低时间和空间复杂度。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2000005;
int n,Q,a[maxn],b[maxn];
struct node{
int L,R,sum;
node* ch[2];
void maintain(){ sum=ch[0]->sum+ch[1]->sum; }
} *rt[maxn], base[maxn], *len=base, nil, *null=&nil;
node* newnode(int L,int R,int sum){
len->L=L; len->R=R; len->sum=sum;
len->ch[0]=len->ch[1]=null;
return len++;
}
node* build(int L,int R){
node* p=newnode(L,R,0);
if(L==R) return p;
int mid=(L+R)>>1;
p->ch[0]=build(L,mid); p->ch[1]=build(mid+1,R);
p->maintain(); return p;
}
node* Updata(node* pre,int val){
node* p=newnode(pre->L,pre->R,pre->sum);
p->ch[0]=pre->ch[0]; p->ch[1]=pre->ch[1];
if(p->L==p->R){
p->sum++; return p;
}
int mid=(p->L+p->R)>>1;
if(val<=mid) p->ch[0]=Updata(p->ch[0],val);
else p->ch[1]=Updata(p->ch[1],val);
p->maintain(); return p;
}
int Query(node* tl,node* tr,int K){
if(tl->L==tl->R) return b[tl->L];
int tem=tr->ch[0]->sum-tl->ch[0]->sum;
if(K<=tem) return Query(tl->ch[0],tr->ch[0],K);
return Query(tl->ch[1],tr->ch[1],K-tem);
}
int find(int x){ return lower_bound(b+1,b+1+b[0],x)-b; }
int main(){
freopen("poj2104.in","r",stdin);
freopen("poj2104.out","w",stdout);
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]), b[++b[0]]=a[i];
sort(b+1,b+1+b[0]);
b[0]=unique(b+1,b+1+b[0])-(b+1);
rt[0]=build(1,b[0]);
for(int i=1;i<=n;i++) rt[i]=Updata(rt[i-1],find(a[i]));
while(Q--){
int x,y,z; scanf("%d%d%d",&x,&y,&z);
printf("%d\n",Query(rt[x-1],rt[y],z));
}
return 0;
}