/**
* @file main.cpp
* @brief 线段树
* 题意大致为:知道插队的每个用户将插到的位置,以及其附带的编号
* 需要还原最终的排队序列
*
* 做法是从最后一个人倒过来往前处理
* 对于最后一人他所谓的插队位置i表示前面有i个空位置需要空出来
* 一次从后往前处理完就得到了最终序列
*
* 这里使用树状数组来进行二分的插入,树状数组的empty表示在该区间上有这么多个空位置
*
* 例如以下的输入数据:
* 4
* 0 77
* 1 51
* 1 33
* 2 69
*
* 先插入69,69之前需要有两个空档,先和[0,1]区间比较,该区间有两个空档,
* 所以69不能插入左子树,而是插入右子树[2,3]区间,
* 69在[2,3]区间的序号变为0,进一步插入到[2]的区间,即找到69的合适位置
* 以上所有步骤同时需要把所有区间的空档位置减一
*
* 0-3[4]
* / \
* 0-1[2] 2-3[2]
* / \ / \
* 0[1] 1[1] 2[1] 3[1]
*
* @author yekeren
* @version 1.0.0
* @date 2013-06-09
*/
#include <stdio.h>
#define LIMIT 200010
#define LEFT(x) (((x) << 1) + 1)
#define RIGHT(x) (((x) << 1) + 2)
///<区间树状数组
struct range_t {
int empty, value;
} k[LIMIT * 4];
///<排队用户
struct person_t {
int ind, value;
} a[LIMIT];
/**
* @brief 初始化所有区间空闲计数
* @param root
* @param left
* @param right
*/
void build(int root, int left, int right)
{
k[root].empty = right - left + 1;
if (left == right) {
return;
}
int mid = (left + right) >> 1;
build(LEFT(root), left, mid);
build(RIGHT(root), mid + 1, right);
}
/**
* @brief 插入一个排队用户
* @param root
* @param left
* @param right
* @param ind
* @param val
*/
void insert(int root, int left, int right, int ind, int val)
{
int mid = (left + right) >> 1;
--k[root].empty;
if (left == right) {
k[root].value = val;
return;
}
if (ind < k[LEFT(root)].empty) {
insert(LEFT(root), left, mid, ind, val);
} else {
insert(RIGHT(root), mid + 1, right, ind - k[LEFT(root)].empty, val);
}
}
/**
* @brief 输出结果
* @param root
* @param left
* @param right
*/
void dump(int root, int left, int right)
{
int mid = (left + right) >> 1;
if (left == right)
{
printf("%d ", k[root].value);
return;
}
dump(LEFT(root), left, mid);
dump(RIGHT(root), mid + 1, right);
}
int main(int argc, char *argv[])
{
int n;
while (scanf("%d", &n) != EOF)
{
for (int i = 0; i < n; ++i) {
scanf("%d%d", &a[i].ind, &a[i].value);
}
build(0, 0, n - 1);
for (int i = n - 1; i >= 0; --i) {
insert(0, 0, n - 1, a[i].ind, a[i].value);
}
dump(0, 0, n - 1);
printf("\n");
}
return 0;
}