链接:点击打开链接
题意:一个长度为N的整数序列,编号0 - N - 1。进行Q次查询,查询编号i至j的所有数中,第K大的数是多少。例如: 1 7 6 3 1。i = 1, j = 3,k = 2,对应的数为7 6 3,第2大的数为6。
代码:
#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 n,m,i,a,b,c; //http://blog.csdn.net/stay_accept/article/details/50492052
while(scanf("%d",&n)!=EOF){
// 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);
scanf("%d",&m);
while(m--){
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",query(a+1,b+1,(b-a+1)-c+1,1,n,0)); //注意是第k大不是第k个数
}
}
return 0;
}