/*
* [这段话转的。。]
* 如果我们从头开始一次做的话,无论是用链表还是数组,肯定会超时(链表寻址时间长,数组移位时间长。)。
* 所以要用一个快速的方法直接找到位置。但是换个角 度,如果我们反过来排,那样的话,我们就知道他所在的
* 精确位置!把存储的结构想象成是链表,插队的人插入后,把他所在的位置从链表中屏蔽掉,然后在新的链 表种
* 继续这样存,这样的话我们就得到了我们想要的顺序!
*
* 按照这种思想,可以用线段树实现。。。
*
*/
#include
<
cstdio
>
using
namespace
std;
const
int
MAXN
=
200000
+
5
;
int
n, p[MAXN], v[MAXN];
int
ans[MAXN], tail;
struct
node{
int
l, r;
int
num, value;
//
num:当前时刻,该区间有多少空位,, value:该区间的人的value(只叶子节点有意义)
};
node tree[MAXN
*
3
];
//
注意*3! 否则 RE!!
//
建树
void
build(
int
i,
int
l,
int
r){
tree[i].l
=
l; tree[i].r
=
r;
tree[i].num
=
r
-
l
+
1
;
//
初始时的空位数
if
(l
==
r)
return
;
int
mid
=
(l
+
r)
>>
1
;
build(i
<<
1
, l, mid);
build(i
<<
1
|
1
, mid
+
1
, r);
}
//
……
void
insert(
int
i,
int
p,
int
v){
tree[i].num
--
;
//
没到一个区间,该区间的空位数-1,
//
因为既然到达该区间,则该人要么在该区间,要么在该区间的子区间。都导致区间的空位数-1
if
(tree[i].l
==
tree[i].r){
//
只叶子节点的value有意义
tree[i].value
=
v;
return
;
}
if
(tree[i
<<
1
].num
>
p)
insert(i
<<
1
, p, v);
else
insert(i
<<
1
|
1
, p
-
tree[i
<<
1
].num, v);
//
减去左子区间的空位数
}
void
cal(
int
i){
if
(tree[i].l
==
tree[i].r){
ans[tail
++
]
=
tree[i].value;
return
;
}
cal(i
<<
1
);
cal(i
<<
1
|
1
);
}
int
main(){
while
(scanf(
"
%d
"
,
&
n)
==
1
){
for
(
int
i
=
0
; i
<
n; i
++
)
scanf(
"
%d %d
"
,
&
p[i],
&
v[i]);
build(
1
,
1
, n);
for
(
int
i
=
n
-
1
; i
>=
0
; i
--
){
insert(
1
, p[i], v[i]);
}
tail
=
0
;
cal(
1
);
printf(
"
%d
"
, ans[
0
]);
for
(
int
i
=
1
; i
<
n; i
++
){
printf(
"
%d
"
, ans[i]);
}
printf(
"
\n
"
);
}
return
0
;
}