poj 2104 K-th Number(划分线段树)

//poj 2104 K-th Number(划分线段树)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=100100;
int st[MAXN];//对所存序列进行排序(取基准元素所用)
struct node
{
    int l,r;
}tree[MAXN*4];//建立线段树所用空间
int arrsub[33][MAXN];
int arrl_len[33][MAXN];//计算多少个进入左孩子
int n,m;
void build(int inode,int l,int r,int deep)
{
    tree[inode].l=l;tree[inode].r=r;
    if(l==r) return ;
    int mid=(l+r)/2;
    int midv=st[mid];
    int ltomid=mid-l+1;
    for(int i=l;i<=r;i++)
    {
        if(arrsub[deep][i]<midv) ltomid--;
    }
    int lto,rto;
    lto=rto=0;
    for(int i=l;i<=r;i++)
    {
        if(i==l)
        {
            arrl_len[deep][i]=0;
        }
        else
        {
            arrl_len[deep][i]=arrl_len[deep][i-1];
        }
        if(arrsub[deep][i]<midv)
        {
            arrl_len[deep][i]++;
            arrsub[deep+1][l+lto++]=arrsub[deep][i];
        }
        else if(arrsub[deep][i]>midv)
        {
            arrsub[deep+1][mid+1+rto++]=arrsub[deep][i];
        }
        else
        {
            if(ltomid>0)
            {
                arrl_len[deep][i]++;
                arrsub[deep+1][l+lto++]=arrsub[deep][i];
                ltomid--;
            }
            else
            {
                arrsub[deep+1][mid+1+rto++]=arrsub[deep][i];
            }

        }
    }
    build(inode*2,l,mid,deep+1);
    build(inode*2+1,mid+1,r,deep+1);
}
int query(int l,int r,int k,int inode ,int deep)
{
    if(l==r) return arrsub[deep][l];
    int sum,ts;
    if(l==tree[inode].l)
    {
        ts=0;
    }
    else
    {
        ts=arrl_len[deep][l-1];
    }
    sum=arrl_len[deep][r]-ts;
    int ls=tree[inode].l;
    int rs=tree[inode].r;
    int mid=(ls+rs)/2;
    if(sum>=k)
    {
         return query(ls+ts, ls+arrl_len[deep][r]-1 , k, inode*2 , deep+1);
    }
    else
    {
        int ee = l - ls + 1 - ts ;
        int e = r - l  - sum ;
        return query(mid+ee , mid+ee+e, k-sum , inode*2+1 ,deep+1);
    }
}
int main()
{
    int a,b,c;
    while(scanf("%d%d",&n,&m)==2)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&st[i]);
            arrsub[1][i]=st[i];
        }
        sort(st+1,st+n+1);
        build(1,1,n,1);
        for(int i=0;i<m;i++){
            scanf("%d %d %d",&a,&b,&c);
            printf("%d\n",query(a,b,c,1,1));
         }
         /*for(int i=1;i<=7;i++)
         {
           printf("%d ",st[i]);
         }
         printf("\n\n");
         for(int i=1;i<=7;i++)
         {
             for(int j=1;j<=7;j++)
             {
                 printf("%d ",arrsub[i][j]);
             }
             printf("\n");
         }
         cout<<endl;
         for(int i=1;i<=7;i++)
         {
             for(int j=1;j<=7;j++)
             {
                printf("%d",arrl_len[i][j]);
             }
            printf("\n");
         }*/
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

u014068781

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值