CF1672I PermutationForces

link

首先有个贪心:假设答案已知,则每次可以任取一个。

令权值 \(c_i = i - p_i\)

首先证明:删除一个数不会使得另一个能删的数变得不能删 (Lemma I)。设 \(i < j\),则可以通过分 \(p_i < p_j\)(显然),\(p_i > p_j\) (分权值正负讨论)两类证明。

然后证明删一个数不会使另一个现在还不能删的数 \(|c_i|\) 变大,方法类似,这样就证明了贪心。

为了避免二分答案,改成每次选 \(|c_i|\) 最小的删掉,并动态维护当前的答案 \(A\)

根据 (Lemma I)\(|c_i| \le A\) 的权值可以不用维护了,当然也不用显式地删除,如果权值变号了可以不维护绝对值的变化,看作 \(|c_i|\) 是负数。

绝对值带来了相当大的麻烦,所以我们一开始就把数分成两类:\(i \le p_i\)\(i > p_i\)。注意到维护的数绝对值的符号不会改变(否则中间存在一个时刻 \(c_i = 0\),从而这个数不被继续维护),分别维护。

\((i, p_i)\) 视为二维平面上的一个点,则删除 \((i, p_i)\) 相当与使得 \(i\) 左上角和右下角的点 \(|c_i|\)\(1\)(删除权值最小的点不会导致其他点权值增大,除非符号改变)。

维护二维平面并不方便,但我们可以维护一定的单调性:设 \(c_i > 0\),则我们只需要维护所有 \(\boldsymbol {c_i > 0}\) \(p_i\) 的前缀最大值(否则一定不是权值最小),对于 \(c_i \le 0\),维护后缀最小值。

由于现在有单调性,矩形加变成了区间加,这样可以直接用线段树维护权值最小值。

用线段树维护区间 min/max 求出前缀最大/后缀最小的变化,每次新加入点时算出 \(c_i\) 即可。复杂度 \(\mathcal O(n \log n)\),常数较大。

实现

posted @ 2022-05-04 16:34  RiverHamster  阅读(96)  评论(0编辑  收藏  举报
\