先将位置信息存入数组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; }