Buy Tickets POJ - 2828

题意:n个人排队, 每个人到的时间不同, 但后来者买到了黄牛票可以插队, 也就是说如果已经排了三个人, 他要插到第二个位置, 原先二三位置的人要向后移动, 最后求出n个人都到齐后对位的顺序(每个人都有特定的编号);

我们可以先安排后来者, 后来者的位置不会因为先来者变动, 但先来者的位置会随着后来者的到来改变;

用线段树, 倒序插入a节点, 若该节点无人, 插入该节点, 反之向后挪动到第一个无人区,其实向后挪动后, 他仍是无人区中第a个位置;

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
using namespace std;
const int maxn = 2e5+100;
int n;
struct node{
    int val, pos;
}a[maxn];
struct Tree{
    int left, right, v;
}tree[maxn<<2];
void build(int m, int l, int r){
    tree[m].left=l;
    tree[m].right=r;
    if(l==r){
        tree[m].v=1;//节点为1表示无人;
        return;
    }
    int mid=(l+r)>>1;
    build(m<<1, l, mid);
    build(m<<1|1, mid+1, r);
    tree[m].v=tree[m<<1].v+tree[m<<1|1].v;
}
int ans[maxn];
void update(int m, int a, int val){
    //printf("m: %d  left:%d   right:%d    a: %d\n", m, tree[m].left, tree[m].right, a);
    if(tree[m].left==tree[m].right){
        tree[m].v=0;//此处插入, 1变0;
        ans[tree[m].left]=val;//记录位置;
        return;
    }
    if(tree[m<<1].v>=a) update(m<<1, a, val); //v>=a说明前半截超过a个空位;
    else update(m<<1|1, a-tree[m<<1].v, val);//前半截不足a个空位, 去后半截找, 此时插入的位置要减去前半截的空位数;
    tree[m].v=tree[m<<1].v+tree[m<<1|1].v;
}
/*
void print(int m){
    if(tree[m].left==tree[m].right){
        printf("m:%d  %d ", m, tree[m].v);
        return;
    }
    print(m<<1);
    print(m<<1|1);
}
*/
int main(){
    while(~scanf("%d", &n)){
        int x, y;
        for(int i=0; i<n; i++){
            scanf("%d%d", &a[i].pos, &a[i].val);
        }
        build(1, 1, n);
        //print(1);
        //printf("\n");
        for(int i=n-1; i>=0; i--){
            update(1, a[i].pos+1, a[i].val);
            //print(1);
            //printf("\n");
        }
        for(int i=1; i<=n; i++){
            printf("%d%c", ans[i], i==n?'\n':' ');
        }
    }
    return 0;
}




猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/80222240