[poj2104]kth-number(归并树求区间第k大)

复杂度:$O(nlog^3n)$

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define MAXN 100000
using namespace std;
int sorted[20][MAXN],a[MAXN];
void build(int deep,int l,int r){
    if(l==r){
        sorted[deep][l]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(deep+1,l,mid);
    build(deep+1,mid+1,r);
    int p=l,q=mid+1,k=l;
    while(p<=mid&&q<=r){
        if(sorted[deep+1][p]<=sorted[deep+1][q])
            sorted[deep][k++]=sorted[deep+1][p++];
        else sorted[deep][k++]=sorted[deep+1][q++];
    }
    while(p<=mid) sorted[deep][k++]=sorted[deep+1][p++];
    while(q<=r) sorted[deep][k++]=sorted[deep+1][q++];//存储序列
}
//查询某个数在区间内的rank
int query(int deep,int l,int r,int tl,int tr,int k){
    if(tr<l||tl>r) return 0;
    if(tl<=l&&r<=tr)
        return lower_bound(&sorted[deep][l],&sorted[deep][r]+1,k)-&sorted[deep][l];
    int mid=(l+r)>>1;
    return query(deep+1,l,mid,tl,tr,k)+query(deep+1,mid+1,r,tl,tr,k);
}

int solve(int n,int tl, int tr, int k){
    int l=1,r=n;
    while(l<r){
        int mid=(l+r+1)>>1;
        int cnt=query(0,1,n,tl,tr,sorted[0][mid]);
        if(cnt<=k) l=mid;
        else r=mid-1;
    }
    return sorted[0][l];
}

int main(){
    int n,m;
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(0,1,n);
    while(m--){
        int tl,tr,k;
        scanf("%d%d%d", &tl, &tr, &k);
        printf("%d\n", solve(n,tl,tr,k-1));
    }
    return 0;
}

 

posted @ 2019-02-26 15:43  Elpsywk  阅读(183)  评论(0编辑  收藏  举报