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));
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值