1. 程式人生 > >2665 Kth number (靜態區間第k大)

2665 Kth number (靜態區間第k大)

Give you a sequence and ask you the kth big number of a inteval. InputThe first line is the number of the test cases. 
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere. 
The second line contains n integers, describe the sequence. 
Each of following m lines contains three integers s, t, k. 
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
OutputFor each test case, output m lines. Each line contains the kth big number. Sample Input
1 
10 1 
1 4 2 3 5 6 7 8 9 0 
1 3 2 
Sample Output
2

#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<memory.h>
#include<queue>
using namespace std;
const int MAXN=100101;

int ls[MAXN*20];//記錄左兒子
int rs[MAXN*20];//記錄右兒子
int sum[MAXN*20];//記錄區間中包含數的個數

int num[MAXN];//原陣列
int sorted[MAXN];//排序並去重後的陣列

int T[MAXN];//記錄第i次操作的根節點(可持久化線段樹)
int n,m,tot=0;//動態開點

//建立一棵空樹,初始狀態為一棵空樹
void build(int l,int r,int &x){
    x=++tot;
    sum[x]=0;
    if(l==r)
        return;
    int m=(l+r)/2;
    build(l,m,ls[x]);
    build(m+1,r,rs[x]);
}

//單點更新
void update(int last,int p,int l,int r,int &x){
    x=++tot;
    ls[x]=ls[last];
    rs[x]=rs[last];
    sum[x]=sum[last]+1;
    if(l==r)
        return;
    int m=(l+r)/2;
    if(p<=m)
        update(ls[last],p,l,m,ls[x]);
    else
        update(rs[last],p,m+1,r,rs[x]);
}

int query(int s,int t,int l,int r,int k){
    if(l==r)
        return l;
    int m=(l+r)/2;
    int cnt=sum[ls[t]]-sum[ls[s]];
    if(k<=cnt)
        return query(ls[s],ls[t],l,m,k);
    return query(rs[s],rs[t],m+1,r,k-cnt);
}



int main(){
    
    int t;
    scanf("%d",&t);
    
    while(t--){
        
        tot=0;
        
        int x,y,z;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&sorted[i]);
            num[i]=sorted[i];
        }
        
        sort(sorted+1,sorted+n+1);
        
        int cnt=unique(sorted+1,sorted+n+1)-sorted-1;
        build(1,cnt,T[0]);
        
        for(int i=1;i<=n;i++)
            num[i]=lower_bound(sorted+1,sorted+cnt+1,num[i])-sorted;//把原陣列修改為在排序過後的陣列的下標
        
        //因為線段樹存的值是數字出現的個數
        for(int i=1;i<=n;i++)
            update(T[i-1],num[i],1,cnt,T[i]);
        
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            printf("%d\n",sorted[query(T[x-1],T[y],1,cnt,z)]);
        }
    }
    
    return 0;
}