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

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/83050814