定期重构
概述
-
有时,我们维护的数据结构是静态的,但题目却要求加/删。
-
如果题目满足元素互相独立,则考虑定期重构吧!
-
加入:将加入但还未整合到数据结构中的元素放入一个栈中,询问时暴力扫这个栈,到达阈值后将栈整合入数据结构,重新 build 一遍即可。
-
删除:考虑反演,我指的是算贡献(这要求贡献满足可减性,不过都独立了,应该都是可减的),将被删除的单独开一个数据结构,对正和负贡献的两个数据结构分别做定期重构即可。
-
-
考虑到复杂度平衡,一般较常见的“定期”是根号次操作。可以基于启发式合并来做启发式重构。替罪羊树有着特殊的重构周期,其依赖平衡因子 \(\alpha\),这主要和其作为树的递归性有关。
根号重构
启发式重构
-
启发式重构是一种颇特殊的定期重构方式。其尝试将合并过程规约到启发式合并的时间复杂度下——也即每个元素只会参与 \(O(\log)\) 次合并,从而获得比根号重构更好的时间复杂度。
-
显然这是不容易的。考虑一个不允许插入的数据结构,不妨取其的构建复杂度为 \(O(siz)\),\(siz\) 为元素个数。当我们把小的数据结构合并到大的中时,小的一方的复杂度是正确的,但既然没法插入则复杂度为 \(O(siz_A+siz_B)\),大的一方的复杂度会炸。
-
解决办法:让两者的 \(siz\) 一样大就好了——回到“每次合并 \(siz\) 翻倍”的证明中去!
-
按二进制维护若干个数据结构,第 \(i\) 个的 \(siz\) 为 \(2^i\)。显然至多有 \(O(\log)\) 个数据结构。
-
每次新加的元素单独开一个数据结构,然后模仿二进制进位过程,不断合并 \(siz\) 相同的数据结构。
-
显然其符合启发式合并的复杂度分析。于是,我们有了 \(O(m\log m+Q\log m)\) 的优秀复杂度,\(m\) 为插入的元素个数,\(Q\) 为询问次数。
-
注意,其优越性依赖 \(m,Q\) 的平衡,若 \(Q=m\sqrt{m}\),则 \(O(m\sqrt{m}+Q)\) 的根号重构反而复杂度更优。
-
CF710F String Set Queries
-
题意略。
-
一眼 AC 自动机,但是 AC 自动机是离线的。
-
考虑使用启发式重构。不删除,另开负贡献数据结构做减法。
-
总复杂度 \(O(\sum |S|\log n)\)。
-
但实际上空间开不下,必须动态开点,动态开点的 AC 自动机想 destruct(我指的是撤销 trie 图)恶心得要死,我根号重构逃课算了(当然这一做法不仅复杂度劣,常数可能还大...)。
-
本题还有一个有趣的根号分析+哈希的做法:通过字符串哈希来做匹配,容易证明不同的长度至多有 \(\sqrt{n}\) 种,于是暴力就是 \(O((\sum |S|)^\frac{3}{2})\) 的。当然也可以根号分治一下,把里面的短串插进 trie 来代替哈希,但显然并不必要。