题解:P10688 Buy Tickets

· · 题解

建议升绿。

可以直接用平衡树暴力做,但杀鸡焉用牛刀,这里介绍二分方法。 考虑将插入序列翻转,那么翻转后的第一行可以确定其位置。那么第二行的插入,如果插入的位置在第一次插入之前,那么说明最后一次插入不会影响到这一次插入。我们直接将其插入对应位置。反之,如若在后,那么要将其向后移动一个位置。 如此反复的,对于当前插入于 $p$ 之后的操作,我们首先计算 $1$ 到 $p$ 中已经确定答案的数量 $c$,在 $p+1$ 开始的第 $c$ 个空位插入当前数即可。 可以用树状数组维护这个操作。寻找空位时用二分。总复杂度 $\mathcal O(n\log^2n)$。 ```cpp for (int i = 1; i <= n; i ++) scanf ("%d%d", pos + i, val + i); for (int i = n; i >= 1; i --) { int left = t.query (pos[i]); int p = pos[i] + 1; int l = p, r = n; int ls = t.query (pos[i]); while (l <= r) { int mid = l + r >> 1; if (t.query (mid) - ls + left <= mid - pos[i] - 1) p = mid, r = mid - 1; else l = mid + 1; } t.add (p, 1); ans[p] = val[i]; } for (int i = 1; i <= n; i ++) printf ("%d ", ans[i]); puts (""); ```