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