poj2828之单点更新

题目意思:

有n个人排队,每个人有个pos值,和value值,表示他可以插到第pos个人的后面,输出最后的队形序列。

 

解题思路:

如果顺着插的话,要移动后面的队列,如果用链表的话,找到插入的位置很费时。

 

如果逆着考虑的话,当前的人插到恰好有pos个空位的最小的地方,就很简单。

用线段树维护区间内空位的个数,如果要求的空位数大于左边区间的空位数,则减去左边的空位数,再在右边查找。

 

总结:抽象出线段树维护的空间很重要。

 

代码:

//如果逆着推的话,就不用移动很多元素了,这是关键,

//用线段树维护区间的空位数,如果左边的空位数不够的话,选择右边(其中把左边占满),知道找到插入的位置

//线段树 抽象出维护的空间 很关键

 

 

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define lson u<<1, l, mid
#define rson u<<1|1, mid+1, r
const int LEN=200010;
int sum[LEN<<2];
int val[LEN], s[LEN][2];
void Build(int u, int l, int r)
{
    sum[u]=r-l+1;//区间右值减区间左值就是这个区间包含的空位置数
    cout << l << " " << r << endl; //cout << endl;
    if( l==r )//到了线段树叶子节点就返回
        return;
    int mid=l+r>>1;
    Build(lson);//遍历左孩子
    Build(rson);//遍历右孩子
}
int Update(int pos, int u, int l, int r)
{
    --sum[u];//先减和一样,因为子区间插入了一个人父区间空位子数肯定少了一个
    if( l==r )//遍历到叶子节点就返回
        return l;//返回插入的人的位置区间,因为左右相等,所以区间变成一个数
    //二分选择查找
    int mid=l+r>>1;
    //如果插入人前面有sum[u<<1]个人,因为这些是空位置,这题的方法是从后往前插入,
    //所以后来逆退插入人的位置后面的人影响不了前面人的插入,则插入到左边区间;
    if( pos<=sum[u<<1] ) return Update(pos, lson);
    //否则插入到右区间,因为左边有sum[u<<1]个空位置,减去这些就是这个人要找的插的位子
    else return Update(pos-sum[u<<1], rson);
    //--sum[u];
}
int main()
{
    int n, i, j, pos;
    while( scanf("%d", &n)!=EOF )
    {
        for(i=0; i<n; i++)
            scanf("%d%d", &s[i][0], &s[i][1]);
        Build(1, 1, n);
        for(i=n-1; i>=0; i--)
        {
            pos=Update(s[i][0]+1, 1, 1, n);//返回值是插入人的位置
            val[pos]=s[i][1];//把插入人的价值赋给这个位置;
            //cout << pos << " " << val[pos] << " ";
        }
        //cout << endl;
        for(i=1; i<n; i++)
            printf("%d ", val[i]);
        printf("%d\n", val[i]);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值