poj 2104

给定一个区间[l,r],求这个区间的第k大的数是多。

划分树的模板题,讲解见:http://blog.youkuaiyun.com/u013983192/article/details/39051671

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 101000
#define MID(a,b) (a+((b-a)>>1))
int n,m;
int sorted[MAX];
struct ptree
{
    int val[MAX];
    int num[MAX];
};
ptree tree[20];
void build_tree(int l,int r,int p)
{
    int i,j;
    if(l==r) return ;
    int mid=MID(l,r);
    int lsame=mid-l+1,same=0,ln=l,rn=mid+1;
    for(i=l;i<=r;i++) if(tree[p].val[i]<sorted[mid]) lsame--;
    for(i=l;i<=r;i++)
    {
        if(i==l) tree[p].num[i]=0;
        else tree[p].num[i]=tree[p].num[i-1];
        if(tree[p].val[i]<sorted[mid])
        {
            tree[p].num[i]++;
            tree[p+1].val[ln++]=tree[p].val[i];
        }
        else if(tree[p].val[i]>sorted[mid])
        {
            tree[p+1].val[rn++]=tree[p].val[i];
        }
        else
        {
            same++;
            if(lsame>=same)
            {
                tree[p].num[i]++;
                tree[p+1].val[ln++]=tree[p].val[i];
            }
            else
            {
                tree[p+1].val[rn++]=tree[p].val[i];
            }
        }
    }
    build_tree(l,mid,p+1);
    build_tree(mid+1,r,p+1);
}
int query(int l,int r,int left,int right,int k,int p)
{
    if(left==right) return tree[p].val[left];
    int mid=MID(left,right);
    int lx,ly,rx,ry;
    /*
        lx表示从lft到st-1这段区间内有多少个数进入左子树
        ly表示从st到ed这段区间内有多少个数进入左子树
        rx表示从lft到st-1这段区间内有多少个数进入右子树
        ry表示从st到ed这段区间内有多少个数进入右子树
     */
    if(l==left)
    {
        lx=0;ly=tree[p].num[r];
    }
    else{
        lx=tree[p].num[l-1];ly=tree[p].num[r]-lx;
    }
    if(k<=ly)
    {
        l=left+lx;
        r=left+lx+ly-1;
        return query(l,r,left,mid,k,p+1);
    }
    else
    {
        rx=l-left-lx;
        ry=r-l+1-ly;
        l=mid+rx+1;
        r=mid+rx+ry;
        return query(l,r,mid+1,right,k-ly,p+1);
    }
}
int main()
{
    int i,j;
    int L,R,k;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)
        {scanf("%d",&tree[0].val[i]);sorted[i]=tree[0].val[i];}
        sort(sorted+1,sorted+n+1);
        build_tree(1,n,0);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&L,&R,&k);
            printf("%d\n",query(L,R,1,n,k,0));
        }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值