POJ 2104 K-th Number(主席树)

本文详细介绍了使用主席树解决特定区间查询问题的实现方法。通过数据排序去重,构建多棵主席树,每棵树记录不同位置的数据出现次数,从而高效地进行区间内第x个数的查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主席树做法,第一次写,1A了。

主要思路为,数据排序去重后,从原始数据第一个添加到最后一个构建n棵树,树上内容为根据排序去重结果的数的出现次数,给定l r 区间,第x个数,用第r减去第l-1的树上,找到需要找的第x个数,输出即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <string>
#include <vector>
//#include <iostream>
using namespace std;


int head[101000],total=0;
struct node{int lson,rson,sum;} tree[3001000];
int inf[101000],num[101000];

int build(int l,int r,int now)
{
    if(l==r)
    return 0;

    total++;
    tree[now].lson=total;
    total++;
    tree[now].rson=total;

    build( l, (l+r)/2, tree[now].lson);
    build( (l+r)/2+1, r, tree[now].rson);

    return 0;
}

int update(int number,int l,int r,int now,int pre)
{
    if(l==r)
    {
        tree[now].sum++;
        return 0;
    }

    int mid=(l+r)/2;
    if(number<=num[mid])
    {
        total++;
        tree[now].lson=total;
        tree[now].rson=tree[pre].rson;

        update(number,l,(l+r)/2,tree[now].lson,tree[pre].lson);
    }
    else
    {
        total++;
        tree[now].rson=total;
        tree[now].lson=tree[pre].lson;
        update(number,(l+r)/2+1,r,tree[now].rson,tree[pre].rson);
    }

    tree[now].sum=tree[tree[now].lson].sum+tree[tree[now].rson].sum;
    return 0;
}

int ques(int pre,int now,int number,int l,int r,int temp)
{
    if(l==r)
    return num[l];

    int mid=(l+r)/2;

    if(tree[tree[now].lson].sum-tree[tree[pre].lson].sum+temp>=number)
    return ques(tree[pre].lson,tree[now].lson,number,l,mid,temp);
    else
    return ques(tree[pre].rson,tree[now].rson,number, mid+1,r,temp+tree[tree[now].lson].sum-tree[tree[pre].lson].sum);

}


int main()
{
    int i,j,n,k,m,l,p;

    scanf("%d%d",&m,&n);

    for(i=1;i<=m;i++)
    {
       scanf("%d",&inf[i]);
       num[i]=inf[i];
    }

    sort(num+1,num+1+m);

    int xx=unique(num+1,num+1+m)-num+1;
    xx--;

    head[0]=total;
    build(1,xx,head[0]);

    for(i=1;i<=m;i++)
    {
        total++;
        head[i]=total;
        update(inf[i],1,xx,head[i],head[i-1]);
    }

    while(n--)
    {
        scanf("%d%d%d",&j,&k,&l);
        printf("%d\n",ques(head[j-1],head[k],l,1,xx,0));
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值