树形结构都有层次之分,我们假设根为第0层。struct node
{
int val[maxn];
int num[maxn];
}tree[30];
建树小结:void build(int ind,int l,int r)
{
if(l == r)//到叶子
return ;
int mid=(l+r)>>1;
int isame=mid-l+1,same=0;
for(int i=l;i<=r;i++)
if(sorted[mid] > tree[ind].val[i])
isame--;//排除比中值小的
int ln=l;//划分给下一层左子树的,开始位置
int rn=mid+1;//划分给下一层右子树的,开始位置
for(int i=l;i<=r;i++)
{
if(l == i)//第一个元素之前没有被划到左子树的,所以初始化为0
{
tree[ind].num[i]=0;
}
else
{
tree[ind].num[i]=tree[ind].num[i-1];
}
if(tree[ind].val[i] > sorted[mid])//如果大于中值,划到右边
{
tree[ind+1].val[rn++]=tree[ind].val[i];
}
else if(tree[ind].val[i] < sorted[mid])//小于中值,分给左边
{
tree[ind+1].val[ln++]=tree[ind].val[i];
tree[ind].num[i]++;
}
else//和中值一样大
{
if(isame >same)//还要划到左边
{
same++;
tree[ind+1].val[ln++]=tree[ind].val[i];
tree[ind].num[i]++;
}
else//划给右边
{
tree[ind+1].val[rn++]=tree[ind].val[i];
}
}
}
build(ind+1,l,mid);//递归左右子树
build(ind+1,mid+1,r);
}
再来看递归到右子树的情况,这个时候要注意递归查的不再是第k大了,而是第k-s1大元素,因为前s1大元素都在左子树了。同样也是递归区间的问题,还是要用到s0和s1,a-l-s0表示区间[l,a-1]里被划到右边的元素,b-a-1-s1表示区[a,b]里被划到右边的元素(减1是为了处理边界问题),右子树的开始位置是mid+1,同上,所以第k-s1大元素至少是从mid+1+a-l-s0开始的,至多在位置mid-l+1+b-s0-s1,至此,递归区间已分析完成。if(s1 >= k)
{
a=l+s0;
b=l+s0+s1-1;
return query(ind+1,l,mid,a,b,k);
}
else
{
a=mid-l+1+a-s0;
b=mid-l+1+b-s0-s1;
return query(ind+1,mid+1,r,a,b,k-s1);
}
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn=100011;
int sorted[maxn];
struct node
{
int val[maxn];
int num[maxn];
}tree[30];
void build(int ind,int l,int r)
{
if(l == r)
return ;
int mid=(l+r)>>1;
int isame=mid-l+1,same=0;
for(int i=l;i<=r;i++)
if(sorted[mid] > tree[ind].val[i])
isame--;
int ln=l;
int rn=mid+1;
for(int i=l;i<=r;i++)
{
if(l == i)
{
tree[ind].num[i]=0;
}
else
{
tree[ind].num[i]=tree[ind].num[i-1];
}
if(tree[ind].val[i] > sorted[mid])
{
tree[ind+1].val[rn++]=tree[ind].val[i];
}
else if(tree[ind].val[i] < sorted[mid])
{
tree[ind+1].val[ln++]=tree[ind].val[i];
tree[ind].num[i]++;
}
else
{
if(isame >same)
{
same++;
tree[ind+1].val[ln++]=tree[ind].val[i];
tree[ind].num[i]++;
}
else
{
tree[ind+1].val[rn++]=tree[ind].val[i];
}
}
}
build(ind+1,l,mid);
build(ind+1,mid+1,r);
}
int query(int ind,int l,int r,int a,int b,int k)//在区间[a,b]里找第k大,现在在区间[l,r]
{
if(a == b)
return tree[ind].val[a];
int s0,s1,mid=(l+r)>>1;
if(a == l)
{
s0=0;
s1=tree[ind].num[b];
}
else
{
s0=tree[ind].num[a-1];
s1=tree[ind].num[b]-s0;
}
if(s1 >= k)
{
a=l+s0;
b=l+s0+s1-1;
return query(ind+1,l,mid,a,b,k);
}
else
{
a=mid-l+1+a-s0;
b=mid-l+1+b-s0-s1;
return query(ind+1,mid+1,r,a,b,k-s1);
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&tree[0].val[i]);
sorted[i]=tree[0].val[i];
}
sort(sorted+1,sorted+n+1);
build(0,1,n);
int x,y,k;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",query(0,1,n,x,y,k));
}
}
return 0;
}