#include #include #include #include using namespace std; const int N = 200010; int n, res[N]; int p[N], v[N]; // 在p[i]的后面,v[i]:权值 struct Node { int l, r; int sum; // 此区间内空位置的数量 } tr[N << 2]; void pushup(int u) { tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum; } void build(int u, int l, int r) { tr[u].l = l, tr[u].r = r; if (l == r) { tr[u].sum = 1; // 每个叶子节点初始化为1,表示此区间内空位置的数量是1 return; } int mid = (l + r) >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); pushup(u); // 叶子有初始值1,所以这里需要向上更新信息 } // 此处的x,是指在第x个空白位置上,不是普通前缀和的第x个位置的概念 void modify(int u, int x, int v) { if (tr[u].l == tr[u].r) { tr[u].sum = 0; // 此点被占用了,区间内空位置数量修改为0 // 注意:因为是魔改的线段树区间和,所以tr[u].l=tr[u].r≠x // x含义:第x个空白位置 res[tr[u].l] = v; // 用结果数组记录最后此位置上是v这个权值 return; } // 下面也是魔改的关键部分: // 如果修改的位置在左侧(左侧空白位置数>=x),递归左子树 if (x <= tr[u << 1].sum) modify(u << 1, x, v); else // 如果在右侧,递归右子树,注意 x 减去 左侧的空白数量 modify(u << 1 | 1, x - tr[u << 1].sum, v); // 更新父节点信息 pushup(u); } /* 参考答案: 77 33 69 51 31492 20523 3890 19243 */ int main() { #ifndef ONLINE_JUDGE freopen("POJ2828.in", "r", stdin); #endif // 加快读入 ios::sync_with_stdio(false), cin.tie(0); while (cin >> n) { build(1, 1, n); // 构建一个叶子节点值为1的线段树,描述此区间内空位置的数量 // p[i]:在p[i]的后面,即p[i]+1的位置上 // v[i]: 权值 for (int i = 1; i <= n; i++) cin >> p[i] >> v[i]; // 倒序枚举,以终为始,这样才不会破坏每个人的位置相对信息概念 for (int i = n; i; i--) modify(1, p[i] + 1, v[i]); // 输出 for (int i = 1; i <= n; i++) printf("%d ", res[i]); puts(""); } return 0; }