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