分析:线段树好题;
观察发现,最后一个人插入的位置是固定的联想到逆序读入,维护一颗线段树,区间存储剩余的位
核心查询代码:(原因理解下面Hint)
if(p<=sum[i<<1])update(p,v,lson);
else update(p-sum[i<<1],v,rson);
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 10;
int sum[maxn<<2], ans[maxn<<2], pos[maxn], val[maxn];
int n;
void pushup(int root){
sum[root] = sum[root<<1] + sum[root<<1|1];
}
void build(int root, int l, int r){
sum[root] = r - l +1; //初始化
if (l == r) return;
int m = (l+r) >> 1;
build(root<<1, l, m);
build(root<<1|1, m+1, r);
}
void update(int root, int l, int r, int pos, int val){
if (l == r){
ans[root] = val;
sum[root] --;
return;
}
int m = (l+r) >> 1;
if (pos <= sum[root<<1]) update(root<<1, l, m, pos, val); //核心部分
else update(root<<1|1, m+1, r, pos-sum[root<<1], val);
pushup(root);
}
int g = 0;
void print(int root, int l, int r){ // 打印叶子结点 可以不处理行末空格
if (l == r){
printf("%d ", ans[root]);
return;
}
int m = (l+r) >> 1;
print(root<<1, l, m);
print(root<<1|1, m+1, r);
}
int main(){
while (scanf("%d", &n) != EOF){
for (int i = 0; i<n; i++)
scanf("%d%d", &pos[i], &val[i]);
build(1, 1, n);
for (int i = n-1; i>=0; i--){
update(1, 1, n, pos[i]+1, val[i]); // pos + 1
}
print(1, 1, n);
puts("");
}
return 0;
}
Hint
线段树节点中保存这一段中的空位数,然后倒序对pos插入:
例如: 0 77
1 51
1 33
2 69
先取: 2 69 —— —— —69— —— (需要前面有3个空位才能插入)
然后取: 1 33 —— —33— —69— —— (需要前面有2个空位才能插入)
然后取: 1 51 —— —33— —69— —51— (需要前面有2个空位才能插入) 前面只有1个空位 故插入后面空格
然后取: 0 77 —77— —33— —69— —51— (需要前面有1个空位才能插入)