线段树端点更新 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;

}




 

 

 

你可能感兴趣的:(poj)