给定一个区间[l,r],求这个区间的第k大的数是多。
划分树的模板题,讲解见:http://blog.youkuaiyun.com/u013983192/article/details/39051671
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 101000
#define MID(a,b) (a+((b-a)>>1))
int n,m;
int sorted[MAX];
struct ptree
{
int val[MAX];
int num[MAX];
};
ptree tree[20];
void build_tree(int l,int r,int p)
{
int i,j;
if(l==r) return ;
int mid=MID(l,r);
int lsame=mid-l+1,same=0,ln=l,rn=mid+1;
for(i=l;i<=r;i++) if(tree[p].val[i]<sorted[mid]) lsame--;
for(i=l;i<=r;i++)
{
if(i==l) tree[p].num[i]=0;
else tree[p].num[i]=tree[p].num[i-1];
if(tree[p].val[i]<sorted[mid])
{
tree[p].num[i]++;
tree[p+1].val[ln++]=tree[p].val[i];
}
else if(tree[p].val[i]>sorted[mid])
{
tree[p+1].val[rn++]=tree[p].val[i];
}
else
{
same++;
if(lsame>=same)
{
tree[p].num[i]++;
tree[p+1].val[ln++]=tree[p].val[i];
}
else
{
tree[p+1].val[rn++]=tree[p].val[i];
}
}
}
build_tree(l,mid,p+1);
build_tree(mid+1,r,p+1);
}
int query(int l,int r,int left,int right,int k,int p)
{
if(left==right) return tree[p].val[left];
int mid=MID(left,right);
int lx,ly,rx,ry;
/*
lx表示从lft到st-1这段区间内有多少个数进入左子树
ly表示从st到ed这段区间内有多少个数进入左子树
rx表示从lft到st-1这段区间内有多少个数进入右子树
ry表示从st到ed这段区间内有多少个数进入右子树
*/
if(l==left)
{
lx=0;ly=tree[p].num[r];
}
else{
lx=tree[p].num[l-1];ly=tree[p].num[r]-lx;
}
if(k<=ly)
{
l=left+lx;
r=left+lx+ly-1;
return query(l,r,left,mid,k,p+1);
}
else
{
rx=l-left-lx;
ry=r-l+1-ly;
l=mid+rx+1;
r=mid+rx+ry;
return query(l,r,mid+1,right,k-ly,p+1);
}
}
int main()
{
int i,j;
int L,R,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
{scanf("%d",&tree[0].val[i]);sorted[i]=tree[0].val[i];}
sort(sorted+1,sorted+n+1);
build_tree(1,n,0);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&L,&R,&k);
printf("%d\n",query(L,R,1,n,k,0));
}
}
return 0;
}