#include <iostream>
#include <cstdio>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int maxn = 200100;
int sum[maxn << 2], id, pos[maxn], val[maxn], ans[maxn];
void PushUp(int rt){
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt){
if (l == r){
sum[rt] = 1;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void query(int k, int l, int r, int rt){
sum[rt] -= 1;
if (l == r){
id = l;
return;
}
int m = (l + r) >> 1;
if (sum[rt << 1] >= k) query(k, lson);
else{
k -= sum[rt << 1];
query(k, rson);
}
}
int main(){
int n;
while (~scanf("%d", &n)){
build(1, n, 1);
for (int i = 1; i <= n; i++) scanf("%d%d", &pos[i], &val[i]);
for (int i = n; i >= 1; i--){
query(pos[i] + 1, 1, n, 1);
ans[id] = val[i];
}
for (int i = 1; i <= n; i++){
printf("%d", ans[i]);
if (i == n) cout << endl;
else printf(" ");
}
}
return 0;
}
题目链接: http://poj.org/problem?id=2828
题目一看好高深啊,不过还好,AC。。
这道题如果正着看,那么每一个人的地方都有可能变动,但是如果倒着看,每一个只要入队了,他的位置就不再改变,这样的话就是一道赤裸裸的线段树单点更新了,每一个结点存储的是该区间内还有多少个空位,每一次遇到一个人的时候,都把他插入到正确的位置,至于怎么算正确的位置,如果当前结点左子树权值大于pos,那么就往左边放,否则就往右边放,放不进去左边的时候,pos要减去左边的空位数,否则的话有可能右边也放不进去,最后根本放不到叶子结点里面。每进入一个区间,该区间的空位数就减少一个,这个千万不要忘了处理。最后用一个数组来存储插入进去以后的最终位置。