先将位置信息存入数组p,然后倒序插入线段树中,然后根据线段树区间空位的信息将v插入ans数组中合适的位置。利用了倒序插入时第i个元素最终在ans中的位置为插入时从ans左往右第i+1个空位处的这个规律。线段树的作用不是存储最后的v,而是为v插入ans中的合适位置提供标准。将查找合适位置的复杂度降到O(logn)
在插入线段树时的标准是,区间左右孩子节点所剩的空位数。
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <ctype.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
const int maxn = 200010;
int tree[maxn << 2];
int p[maxn], v[maxn], ans[maxn];
void PushUP(int rt) {
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
void build(int l, int r, int rt) {
if (l == r) {
tree[rt] = 1; ///开始的时候初始化每个节点存储量为1
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUP(rt);
}
void update(int p, int v, int l, int r, int rt) {
if (l == r) {
ans[l] = v; ///根据线段树找到了v在ans中的合适位置,插入
tree[rt] = 0; ///此时v占了这个点的位置,将这个叶节点的容量置0
return ;
}
int m = (l + r) >> 1;
if (p <= tree[rt << 1]) update(p, v, lson); ///此时若左子树的空位足够多,则递归插入左子树
else update(p - tree[rt << 1], v, rson); ///否则,算上左子树的空位,将剩下的空位利用右子树进行递归插入
PushUP(rt);
}
int main()
{
int N;
while(~scanf("%d", &N)) {
build(1, N, 1);
for (int i = 1; i <= N; i++) {
scanf("%d%d", &p[i], &v[i]);
}
for (int i = N; i >= 1; i--) {
update(p[i] + 1, v[i], 1, N, 1); ///此处倒序进行插入,原因是便于确定最后节点的位置
}
for (int i = 1; i <= N - 1; i++) {
printf("%d ", ans[i]);
}
printf("%d\n", ans[N]);
}
return 0;
}