POJ2828 Buy Tickets

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

给出插队的信息(插到当前第几个人后面),求最终的序列。

权值树状数组。

考虑人越靠后优先级越高(如最后一个人的最终位置就是他插入的位置),所以倒序处理。

用1表示还没人在最终的这个位置,0表示有人了。

  倒序到i的时候,“ i 插到第k个人后面”,指的是 i 前面有k个空位且 i 自己也在一个空位上。也就是第一个前面有k个1的位置。

  用树状数组维护前缀和,就能二分了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2e5+5;
int n,pos[N],val[N],c[N],ans[N];
void add(int x)
{
    for(;x<=n;x+=(x&-x))
        c[x]++;
}
int query(int x)
{
    int ret=0;
    for(;x;x-=(x&-x))
        ret+=c[x];
    return ret;
}
void cnc(int x)
{
    for(;x<=n;x+=(x&-x))
        c[x]--;
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        for(int i=1;i<=n;i++)add(i),scanf("%d%d",&pos[i],&val[i]);
        for(int i=n;i;i--)
        {
            int l=0,r=n,k;
            while(l<=r)
            {
                int mid=((l+r)>>1);
                if(query(mid)>=pos[i]+1)k=mid,r=mid-1;
                else l=mid+1;
            }
            cnc(k);ans[k]=i;
        }
        for(int i=1;i<=n;i++)printf("%d ",val[ans[i]]);
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/8969369.html