Buy Tickets POJ - 2828 线段树 点修改

本文介绍了一种使用线段树数据结构解决购票排队问题的方法。通过从后向前插入人员,并利用线段树更新剩余位置,实现了高效地确定最终序列中每个位置对应的价值。文章详细解释了算法思路及实现过程。

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

题意

有N个人排名买票,现在给出每个人要插入的位置pos(0<=pos<=N-1)以及他的价值val。在插入N个人后,会构成一个新序列。现在让你按顺序 输出新序列中每个位置pos对应的价值val

思路

最后一次插入某个位置的人,他的位置不会再改变,所以我们应该从后往前插入。用sum记录所在空间剩余的位置。对于插入在pos位置的人他前边一定要有pos-1(1~n 建树)个剩余位置。(0~n 建树则为 pos个剩余位置)

访问结点时,如果左子树的剩余位置大于或等于 pos 就访问左子树(sum[rt<<1] >= pos),否则就访问右子树。访问右子树时需要用pos减去左子树的剩余位置( pos-sum[rt<<1] ),即整个线段树的第pos个空位(空叶子结点),也是在右儿子那的第pos-sum[rt<<1]个空位。

#include<cstdio>
const int maxn=200000;
int sum[maxn<<2],pos[maxn<<2],val[maxn<<2],ans[maxn<<2];  //ans存储插入的值
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bulid(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=1;    //初始化每个叶子结点剩余位置为 1
        return ;
    }
    int m=(l+r)>>1;
    bulid(l,m,rt<<1);
    bulid(m+1,r,rt<<1|1);
    pushup(rt);
}
void update(int p,int v,int l,int r,int rt)
{
    if(l==r)
    {
        ans[rt]=v;
        sum[rt]--;
        return ;
    }
    int m=(l+r)>>1;
    if(sum[rt<<1]>=p)     //判断插入左子树还是右子树
        update(p,v,l,m,rt<<1);
    else
        update(p-sum[rt<<1],v,m+1,r,rt<<1|1);
    pushup(rt);
}
void print(int l,int r,int rt)
{
    if(l==r)
    {
        printf("%d ",ans[rt]);
        return ;
    }
    int m=(l+r)>>1;
    print(l,m,rt<<1);
    print(m+1,r,rt<<1|1);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        bulid(1,n,1);
        for(int i=0;i<n;i++)
            scanf("%d%d",&pos[i],&val[i]);
        for(int i=n-1;i>=0;i--)
            update(pos[i]+1,val[i],1,n,1);
        print(1,n,1);
        printf("\n");
    }
    return 0;
}

参考博客

http://www.cnblogs.com/ACMan/archive/2012/07/11/2586793.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值