POJ 2828 逆向思維+線段樹
阿新 • • 發佈:2018-11-03
因為後面的人會影響去前面人的位置,(如果後面的人插在前面的人的位置,那麼前面的人的位置就會向後移動),那麼我們從後往前插入處理,這樣保證插入後不會變化。用線段樹的每個節點記錄這個區間的空位置數,每次插入的時候將這個人放在第pos[i]個空格的地方, 因為後面的人如果排在前面人的前面,那麼我們對前面的人進行操作的時候.那個位置就被佔了,前面的人的位置就會向後移一格。這樣,我們就可以用線段樹進行維護了,每次查詢第pos[i]個空格的位置,然後再改變表示pos[i]位置的節點狀態。
該線段樹中每個節點的狀態值為所代表的區間的空位置數,初始化為區間長度。
#include<cstdio> using namespace std; const int maxn=2e5+10; int tree[maxn<<2]; int id,ans[maxn],pos[maxn],val[maxn]; void build(int l,int r,int i){ tree[i]=r-l+1; if(l==r) return ; int mid=((l+r)>>1); build(l,mid,i<<1); build(mid+1,r,i<<1|1); } void update(int p,int l,int r,int i){ tree[i]--; if(l==r){ id=l; return; } int mid=((l+r)>>1); if(tree[i<<1]>=p){ update(p,l,mid,i<<1); }else{ p-=tree[i<<1]; update(p,mid+1,r,i<<1|1); } } int main(){ int n; while(scanf("%d",&n)!=EOF){ build(1,n,1); for(int i=1;i<=n;i++){ scanf("%d%d",&pos[i],&val[i]); } for(int i=n;i>=1;i--){ update(pos[i]+1,1,n,1); ans[id]=val[i]; } printf("%d",ans[1]); for(int i=2;i<=n;i++){ printf(" %d",ans[i]); } puts(""); } return 0; }