题目大意
给NNN个操作。
1.插入一个串SSS。
2.删除一个串SSS 。
3.询问未被删除的串在SSS中出现的次数。
∑∣S∣≤3e5\sum |S| \leq 3e5∑∣S∣≤3e5,强制在线。
Solution
此题有多种解法,这里例举说明几种。(设LLL为总长)
Solution 1
如果不强制在线,那么ACACAC自动机,后缀自动机都可以做此问题。(对于删除可以再建一个专门的删除的串的自动机,然后答案相减)现在考虑如果强制在线,发现并不好维护,但是由于每个串之间的贡献相互独立,所以可以用到一个很好的技巧:二进制分组。
大意是这样的:假设现在有qqq个串,我们维护logloglog个自动机,对于q的二进制q0q1...qxq_0q_1...q_xq0q1...qx,如果qiq_iqi为111,那么第iii个自动机就是2i2^i2i个串的自动机。相当于说将qqq个串分到logloglog个组中,分组的依据就是qqq的二进制拆分。那么假设我们现在要插入第q+1q+1q+1个串,那么类似二进制进位,每次暴力重构即可。
具体的,(在插入q+1q+1q+1之前)如果第000个自动机存了111个串,那么将其合并到第111个自动机(同时清空第000个自动机),在这之后,如果第111个自动机存了222个串,那么将其合并到第222个自动机(同时清空第111个自动机),依次类推。每次合并直接暴力重构。
复杂度分析也很明显,一个串最多被重构logloglog次(因为每次重构都要向后移动一位,只有logloglog位),所以复杂度是对的。
Solution 1.1
用ACACAC自动机即可
Solution 1.2
用后缀自动机。
Solution 2
考虑用后缀自动机怎么做,是不是每次查询failfailfail树上到根的链?所以我们用lctlctlct维护failfailfail树即可。
注意在线构造后缀自动机要判这个节点是否存在以及在线构造复杂度上界是O(LL)O(L\sqrt{L})O(LL)。
复杂度O(LL+LlogL)O(L \sqrt{L} + LlogL)O(LL+LlogL)
Solution 3
考虑根号分治,常见的,如果一个串长度大于L\sqrt{L}L,那么这样的串不会超过L\sqrt{L}L个,否则其长度会小于L\sqrt{L}L。
Solution 3.1
对于插入的一个串,如果长度大于L\sqrt{L}L,那么对其建出KMPKMPKMP数组。否则将其插入trietrietrie中。
对于查询,对于长度大于根号的,直接KMPKMPKMP跑,注意此时复杂度是L×lenask\sqrt{L} \times len_{ask}L×lenask。然后对于长度小于根号的,直接枚举查询串的一个后缀,然后直接在trietrietrie上走,注意到这里trietrietrie的深度小于L\sqrt{L}L。
所以总的复杂度LLL\sqrt{L}LL
Solution 3.2
考虑后缀自动机。对于一个串,如果其长度小于L\sqrt{L}L,那么直接在自动机上跳failfailfail暴力查询,这样复杂度为len2len^2len2。否则直接在后缀自动机上把相关的链的值重新算一遍(即dfsdfsdfs一遍),这种操作不超过L\sqrt{L}L次。所以总的复杂度还是L\sqrt{L}L。