UOJ #749. -【UNR #6】稳健型选手(猫树分治+主席树)
首先考虑贪心。假设我们现在有一个序列,我们已经维护了它哪些元素选了,哪些元素没选,那么我们可以支持在开头加入两个数,或者在结尾插入两个数,以在结尾插入为例,那么我们先假设它们都选,然后 pop 掉最小的元素即可,不难发现这样恰好会取走 \(\lceil\dfrac{n}{2}\rceil\) 个元素。在开头插入也是同理的。
这样我们知道了如何在开头和结尾插入元素,但是对于这种区间查询的题,我们还需要知道如何合并两个集合的信息才能做到高效区间查询。考虑如何合并,我们假设 \(S\) 为左边选了的集合,\(T\) 为右边没有选的集合,那么最优策略一定是从左边 undo 掉一个集合 \(S'\),右边选上一个集合 \(T'\),满足 \(|S|=|T|\) 且 \(\max S'<\min T'\),答案加上 \(\sum\limits_{x\in T'}x-\sum\limits_{x\in S'}x\)。但是很遗憾的是,这样影响的元素个数是线性的,因此如果想合并两层以上复杂度就会爆炸。幸运的是,如果我们只进行一次合并,那么我们不用维护哪些元素的状态改变了,只用维护答案的增量 \(\sum\limits_{x\in T'}x-\sum\limits_{x\in S'}x\)。如果我们使用了线段树维护选了和没选的点集,那么这个操作可以直接线段树上二分然后查个前缀和求得。
那么有什么东西能够支持多次插入单次合并呢?猫树分治。具体来说每次分治我们处理跨区间的询问,这显然只需要进行一次合并,而每次我们需要维护 \([l,mid]\) 和 \([mid+1,r]\) 所有前缀最优策略中选择的集合,根据前面的分析,每次多两个元素只会影响 \(O(1)\) 个元素的状态,可以使用主席树维护这个继承关系,线段树上二分也要相应地改成主席树上二分。
时间复杂度 \((n+q)\log^2n\)。