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