1. 程式人生 > >hdu 2665 Kth number 劃分樹

hdu 2665 Kth number 劃分樹

求區間第k大元素的值,

看程式碼的註釋。


#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define M 100001
#define md(x,y) (((x)+(y))>>1)
int sorted[M];
struct node{
    int val[M];    //儲存的是當前層的各個位上的數值
    int num[M];     //記錄比當前元素小的元素的和
    double sum[M];  //記錄當前元素之前進入左子樹的元素和
}t[20]; //樹的深度

void build(int lft,int rht,int p)
{
    if(lft==rht) return;
    int i,mid=md(lft,rht);
    int isame=mid-lft+1,same=0;
    //isame 記錄分到左孩子的個數
    for(i=lft;i<=rht;i++)
        if(t[p].val[i]<sorted[mid]) isame--;
    //先算下等於中間值的有幾個
    int ln=lft,rn=mid+1;
    for(i=lft;i<=rht;i++){
        if(i==lft){
            t[p].num[i]=0;
            t[p].sum[i]=0;
        }else{
            t[p].num[i]=t[p].num[i-1];
            t[p].sum[i]=t[p].sum[i-1];
        }
//如果大於,肯定進入右孩子,小於一定進入左孩子。
        if(t[p].val[i]<sorted[mid]){
            t[p].num[i]++;
            t[p].sum[i]+=t[p].val[i];
            t[p+1].val[ln++]=t[p].val[i];
        }else if(t[p].val[i]>sorted[mid]){
            t[p+1].val[rn++]=t[p].val[i];
        }else{
        //處理相等的時候的情況
            if(same<isame){
                same++;
                t[p].num[i]++;
                t[p].sum[i]+=t[p].val[i];
                t[p+1].val[ln++]=t[p].val[i];
            }
            else{
                t[p+1].val[rn++]=t[p].val[i];
            }
        }
    }

    build(lft,mid,p+1);
    build(mid+1,rht,p+1);
}

double sum=0;
int query(int a,int b,int k,int p,int lft,int rht)
{
    if(lft==rht) return t[p].val[a];
    int s,ss,bb,b2; //s記錄[a,b]進入做孩子的元素個數,ss記錄[lft,a-1)中計入左孩子的元素的個數。sss記錄區間[a,b]中小於第k大元素的和.b2表示[lft,a-1]中分到右孩子的個數,bb表示[a,b]中分到右孩子的個數
    double sss;
    int mid=md(lft,rht);
    if(a==lft){
        s=t[p].num[b];
        ss=0;
        sss=t[p].sum[b];
    }else{
        s=t[p].num[b]- t[p].num[a-1];
        ss=t[p].num[a-1];
        sss=t[p].sum[b]-t[p].sum[a-1];
    }
    if(s>=k){
         a= lft+ss;
         b= lft+ss+s-1;
         return query(a,b,k,p+1,lft,mid);
    }else{
        bb=a-lft-ss;
        b2=b-a-s;
        a=mid+bb+1;
        b=mid+1+bb+b2;
        sum+=sss;
        return query(a,b,k-s,p+1,mid+1,rht);   //在右孩子中
    }
}
int main()
{
    int w,i;
    scanf("%d",&w);
    while(w--){
        int n,k;
        scanf("%d%d",&n,&k);
        for(i=1;i<=n;i++){
            scanf("%d",&t[0].val[i]);
            sorted[i]=t[0].val[i];
        }
        sort(sorted+1,sorted+1+n);
        build(1,n,0);
        for(i=1;i<=k;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            printf("%d\n",query(a,b,c,0,1,n));
        }
    }
}