poj2828 Buy Tickets——倒序处理

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

这题可以倒序来做,因为越靠后的人实际上优先级越高;

用0和1表示这个位置上是否已经有人,0表示有,1表示没有,这样树状数组维护前缀和表示这个位置前面有多少个空位置;

每插入一个人,找到前面空位置恰好是他要求的个数的那个位置,就是他最终站的位置(若位置不空则表示后面的人之后插队到他前面了,所以他被挤到后面去);

找到位置后把该位置的值赋成0,表示这里也站了人,倒着处理即可。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const MAXN=200005;
int n,val[MAXN],f[MAXN],x[MAXN],pos[MAXN];
int query(int x)
{
    int s=0;
    for(;x;x-=(x&-x))
        s+=f[x];
    return s;
}
void add(int x,int w)
{
    for(;x<=n;x+=(x&-x))
        f[x]+=w;
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        memset(pos,0,sizeof pos);
        for(int i=1;i<=n;i++)add(i,1);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&x[i],&val[i]);
        for(int i=n;i;i--)
        {
            int l=1,r=n,p;
            while(l<=r)
            {
                int mid=((l+r)>>1);
                if(query(mid)>=x[i]+1)p=mid,r=mid-1;
                else l=mid+1;
            }
            pos[p]=i;
            add(p,-1);
        }
        for(int i=1;i<=n;i++)
            printf("%d ",val[pos[i]]);
        printf("\n");
    }
    return 0;
}

 

posted @ 2018-04-28 18:50  Zinn  阅读(158)  评论(0编辑  收藏  举报