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; }