1. 程式人生 > >POJ 2828 逆向思維+線段樹

POJ 2828 逆向思維+線段樹

因為後面的人會影響去前面人的位置,(如果後面的人插在前面的人的位置,那麼前面的人的位置就會向後移動),那麼我們從後往前插入處理,這樣保證插入後不會變化。用線段樹的每個節點記錄這個區間的空位置數,每次插入的時候將這個人放在第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;
}