每次查找二分出某个数,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; }