POJ2828 Buy Tickets(樹形DP)

// http://www.cnblogs.com/shenben/p/5624886.html
//  思路:根據題目可知,最後插入的位置的數纔是最終不變的數,
// 所以可以從最後的輸入作第1個放入,依此類推,倒插入。
// 在插入時也有一定的技術,首先創建一棵空線段樹時,每個節點
// 記錄當前範圍內有多少個空位置。在插入時,要注意,一個數放
// 入之後那麼這個位置就不用管了,那麼樹中所有的空位置就是餘
// 下的數所對應的位置,也就是把餘下的數又可以看作是一個新的
// 集合。那麼每次插入都是當前集合的第1次放。

#include<iostream>
#include<cstdio>

using namespace std;
const int N=200005;

int n,id,pos[N],val[N],ans[N],w[N*3];

void build(int k,int left,int right){
    w[k]=right-left+1;  //  w記錄這個區間有多少的空位。
    int mid=(left+right>>1);
    if(left<right){
        build(k<<1,left,mid);
        build(k<<1|1,mid+1,right);
    }
}

void updata(int k,int pos,int l,int r){
    w[k]--;//  這個區間增加了一人,區間空位-1。
    if(l==r){
        id=l;return;
    }
    int mid=(l+r)/2;
    if(w[k<<1]>=pos) updata(k<<1,pos,l,mid);
    else{
        pos-=w[k<<1];
        updata(k<<1|1,pos,mid+1,r);
    }
}

int main(){

    freopen("a.txt","r",stdin);

    while(scanf("%d",&n)==1){
        build(1,1,n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&pos[i],&val[i]);
        for(int i=n;i>=1;i--){
            updata(1,pos[i]+1,1,n);
            ans[id]=val[i];
        }
        for(int i=1;i<=n;i++)
            printf("%d ",ans[i]);
        putchar('\n');
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章