每次查找二分出某个数,logn时间在树中找到它的区间,二分找比它小的数的个数,三次二分= (log n)^3
解决的问题:查询某个区间内第k大的数
值得注意的是:
1.归并树,划分树都只能解决元素不重复的情况
2.多个x有相同rank的时候取最大的x
这些相同rank的数组成一个序列A1,A2,……An,之间两两不同,因为没有重复元素
若答案不是An而是Ai(1<=i<n),则An的rank应该是rank(An)+1,这与已知矛盾
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define N 100500
#define M 5500
struct node
{
int l,r,rank;
}tree[3*N];
int ha[20][N];
int n,m;
void build(int pos,int l,int r,int rank)
{
tree[pos].rank=rank;
tree[pos].l=l;tree[pos].r=r;
if(l==r)
{
ha[rank][l]=ha[0][l];
return;
}
int mid=(l+r)>>1;
build(pos*2,l,mid,rank+1);
build(pos*2+1,mid+1,r,rank+1);
int i=l,j=mid+1,cnt=l;
while(i<=mid&&j<=r)
{
if(ha[rank+1][i]<ha[rank+1][j])
ha[rank][cnt++]=ha[rank+1][i++];
else ha[rank][cnt++]=ha[rank+1][j++];
}
while(i<=mid) ha[rank][cnt++]=ha[rank+1][i++];
while(j<=r) ha[rank][cnt++]=ha[rank+1][j++];
}
int query(int pos,int l,int r,int x)
{
if(tree[pos].l==l&&tree[pos].r==r)
{
int num=lower_bound(ha[tree[pos].rank]+tree[pos].l,ha[tree[pos].rank]+tree[pos].r+1,x)-(ha[tree[pos].rank]+tree[pos].l);
return num;
}
int mid=(tree[pos].l+tree[pos].r)>>1;
int c1=0,c2=0;
if(r<=mid)
c1=query(pos*2,l,r,x);
else if(l>mid)
c2=query(pos*2+1,l,r,x);
else
{
c1=query(pos*2,l,mid,x);
c2=query(pos*2+1,mid+1,r,x);
}
return c1+c2;
}
int main ()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;++i)
scanf("%d",&ha[0][i]);
build(1,1,n,0);
int ll,rr,k;
while(m--)
{
scanf("%d%d%d",&ll,&rr,&k);
int l=1,r=n,mid;int res,re;
while(l<=r)
{
mid=(l+r)/2;
res=query(1,ll,rr,ha[0][mid])+1;
if(res<=k)
{
re=mid;
l=mid+1;
}
else r=mid-1; // 为了返回有相同排位的数中最大的一个,二分细节中很多要注意
}
printf("%d\n",ha[0][re]);
}
}
//system("pause");
return 0;
}