题链:
http://poj.org/problem?id=2828
题解:
线段树。
逆向考虑这个过程。最后的序列S共有n个元素。
先看最后一个人,如果他插入到第i位,那么他最终的位置就是当前序列S的第i号位置,然后把这个位置去掉,得到新序列S‘。
再按上面的操作确定倒数第二个人的位置:
如果他插入到第j位,那么他就在新序列S‘的第j个位置。
。。。。。。以此类推,可以确定出所有人的位置。
可以用线段树去确定位置。
代码:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 200050 using namespace std; struct People{ int p,d; }P[MAXN]; struct SGT{ int ls[MAXN<<1],rs[MAXN<<1],siz[MAXN<<1],sz,rt; void build(int &u,int l,int r){ u=++sz; siz[u]=r-l+1; if(l==r) return; int mid=(l+r)/2; build(ls[u],l,mid); build(rs[u],mid+1,r); } void Reset(int n){ sz=rt=0; build(rt,1,n); } int Modify(int u,int l,int r,int k){ siz[u]--; if(l==r) return l; int mid=(l+r)/2; if(k<=siz[ls[u]]) return Modify(ls[u],l,mid,k); else return Modify(rs[u],mid+1,r,k-siz[ls[u]]); } }DT; int ANS[MAXN]; int main(){ int n; while(~scanf("%d",&n)){ DT.Reset(n); for(int i=1;i<=n;i++) scanf("%d%d",&P[i].p,&P[i].d); for(int i=n,p;i;i--){ p=DT.Modify(DT.rt,1,n,P[i].p+1); ANS[p]=P[i].d; } for(int i=1;i<n;i++) printf("%d ",ANS[i]); if(n) printf("%d\n",ANS[n]); } return 0; }