题解 P5066 【[Ynoi2014]人人本着正义之名】
Update:感谢 _Guoyh_ 神仙的提醒,来更题解了。
Problem:
给定一个序列
Solution:
这个东西看上去显然是十分不可做的。。。
于是看了一遍番,发现你还是不会做
所以我们先考虑
数据随机+区间赋值,显然的珂朵莉树。
于是直接珂朵莉树暴力维护就可以拿到
我们从这个解法中挖掘到一个性质:每次区间与/或上相邻的数相当于极长连续同色子段的扩散与收缩。
比如
提取出极长连续子段:
然后对整个区间执行
发现,这个操作其实就是
手模一下,可以发现
然后我们就可以手写一个平衡树来维护这些子段,因为这个操作等价于左端点
具体来说,每一个子段存储:该节点对应的左右端点、子段的值、子树对应的区间的和,子树内
为了方便起见维护了一下子树的 size,但是其实可以计算得到。
但是我们注意到两点:1. 如果有两个连续的同色子段,会同时扩散/收缩,但显然其中一个不应该扩散/收缩;2. 有可能产生长度为
第一个问题没有什么比较好的解决方法,必须保证子段极长。具体来说,我们不去将一个极长段拆成两个。
如何做到这一点呢?我们首先考虑
这里以
那么
以
对于
于是我们只要在一开始按照极长子段建好树就可以保证这些子段一直是极长的了~
那么第 2 个问题怎么解决?
定义势能
所以这棵树的最大势能是
我们考虑暴力删去这些
这样最坏情况下是删去了边界上的点,势能
相当于使用
显然你只有
前面说要维护最小长度,目的就是
对
使用 FHQ-Treap 实现,这道题就做完了~
时间
注意这题我强烈建议不要用 splay,常数会很大,而且因为不支持 split 会导致很难写。
这个写法空间常数略大,有两种解决方法:一,二分取一个值,我取的是
二,写一个垃圾回收,这样空间可以直接取
最终 6.43s/302.95MB 通过本题。
平衡树部分的代码,供参考
Credit:
感谢 noip 在春令营课上讲解大致做法。
感谢 万万没想到 的 FHQ-Treap 学习笔记和解法。
最后留下纪念:
公元 2020 年 4 月 6 日,北京时间 20 点 13 分 21 秒,洛谷用户 ClCN 在经过 20 小时的奋战之后,成功 AC P5066 [Ynoi2014]人人本着正义之名。
以此纪念。