线段树端点更新 poj 2828 Buy Tickets

 

题目链接:

http://poj.org/problem?id=2828

 

题目意思:

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

 

解题思路:

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

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

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

 

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

 

代码:

//如果逆着推的话,就不用移动很多元素了,这是关键,
//用线段树维护区间的空位数,如果左边的空位数不够的话,选择右边(其中把左边占满),知道找到插入的位置
//线段树 抽象出维护的空间 很关键

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF (1<<30)
#define PI acos(-1.0)
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 210000

int sum[maxn*4];
int pos[maxn],value[maxn],ans[maxn],n;
int temp;
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
void build(int l,int r,int rt)
{
    sum[rt]=r-l+1; //初始区间空位的多少
    if(r==l)
        return ;
    int m=(l+r)>>1;

    build(lson);
    build(rson);
}

void update(int target,int l,int r,int rt)
{
    sum[rt]--;   //所到之处,空位数减一,因为必须在某个区间插
    if(l==r)
    {
        temp=l; //找到空位的位置,记住然后进行插入
        return ;
    }

    int m=(l+r)>>1;

    if(target<=sum[rt<<1])  //如果左区间的空位数够的话,在左区间更新
        update(target,lson);
    else
        update(target-sum[rt<<1],rson); //左区间不够,先把左区间占满,然后在填右区间
    return ;
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d",&pos[i],&value[i]);
        build(1,n,1);

        for(int i=n;i>=1;i--)
        {
            update(pos[i]+1,1,n,1);
            ans[temp]=value[i];  //把位置找到然后插入
        }
        printf("%d",ans[1]);
        for(int i=2;i<=n;i++)
            printf(" %d",ans[i]);
        putchar('\n');
    }
    return 0;
}


 

 

 

posted @ 2013-04-04 11:32  xinyuyuanm  阅读(127)  评论(0编辑  收藏  举报