链接:点击打开链接
题意:求给定区间中第k小的数
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int SIZE=100005;
int tmp[SIZE],toleft[50][SIZE];
int tree[50][SIZE];
void build(int l,int r,int rt){
int i,mid,sum,lpos,rpos;
if(l==r)
return;
mid=(l+r)>>1;
sum=mid-l+1;
for(i=l;i<=r;i++)
if(tree[rt][i]<tmp[mid])
sum--;
lpos=l,rpos=mid+1;
for(i=l;i<=r;i++){
if(tree[rt][i]<tmp[mid])
tree[rt+1][lpos++]=tree[rt][i];
else if(tree[rt][i]==tmp[mid]&&sum>0){
tree[rt+1][lpos++]=tree[rt][i];
sum--;
}
else
tree[rt+1][rpos++]=tree[rt][i];
toleft[rt][i]=toleft[rt][l-1]+lpos-l;
}
build(l,mid,rt+1);
build(mid+1,r,rt+1);
}
int query(int L,int R,int k,int l,int r,int rt){
int mid,newl,newr,cnt;
if(L==R)
return tree[rt][L];
mid=(l+r)>>1;
cnt=toleft[rt][R]-toleft[rt][L-1];
if(cnt>=k){
newl=l+toleft[rt][L-1]-toleft[rt][l-1];
newr=newl+cnt-1;
return query(newl,newr,k,l,mid,rt+1);
}
else{
newr=R+toleft[rt][r]-toleft[rt][R];
newl=newr-(R-L-cnt);
return query(newl,newr,k-cnt,mid+1,r,rt+1);
}
} //划分树模板
int main(){ //详见poj2104
int t,n,m,i,a,b,c; //http://blog.csdn.net/stay_accept/article/details/50492052
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(tree,0,sizeof(tree));
for(i=1;i<=n;i++){
scanf("%d",&tree[0][i]);
tmp[i]=tree[0][i];
}
sort(tmp+1,tmp+n+1);
build(1,n,0);
while(m--){
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",query(a,b,c,1,n,0));
}
}
return 0;
}