cf914f-solution
CF914F Solution
题意:
给你一个字符串 \(s\),\(m\) 次操作,每次操作为以下两种之一:
1 i c:令 \(s_i\gets c\)。
2 l r t:求字符串 \(t\) 在 \(s\) 的子串 \(s_{l\dots r}\) 中的出现次数。
\(1\le|s|,m,q,\sum|t|\le10^5\)。
由于要统计出现次数,我们考虑用 SAM 解决。
但是由于询问的是一个区间,对整串建 SAM 不太可行。
考虑把 \(s\) 拆成几块分别建 SAM。假设以 \(B\) 为块长,对每个块建立 SAM。
由于跑 SAM 的复杂度与模式串串长有关,我们对 \(|t|\) 进行分治:
-
若 \(|t|>B\),这样的串数不会超过 \(\dfrac{\sum|t|}B\) 个。我们直接使用 kmp 找匹配,复杂度 \(\mathcal O(\dfrac{\sum|t|}Bn)\)。
-
若 \(|t|\le B\),我们分开算 \([l,r]\) 中整块和散块的贡献:
先算在整块内且不跨块的字符串贡献,这部分可以用 SAM 计算。把模式串放在 \(\mathcal O(\dfrac n B)\) 个 SAM 上跑,复杂度 \(\mathcal O(\sum|t|\dfrac n B)\)。
散块且不跨块的贡献容易处理,用 kmp 暴力求即可。复杂度 \(\mathcal O(qB)\)
最后剩下跨两个块边界的贡献。块边界共有 \(\mathcal O(\dfrac n B)\) 个,每个边界只需要考虑 \(2|t|\) 长度的位置,也用 kmp 求,复杂度 \(\mathcal O(\sum|t|\dfrac n B)\)。
至此询问已处理完毕,至于修改操作,我们只需要暴力重构 \(i\) 所在块内的 SAM,复杂度 \(\mathcal O(qB)\)。
最后总复杂度为 \(\mathcal O(\sum|t|\dfrac n B+qB)\),取 \(B=\sqrt n\) 得到最优复杂度线性根号。

浙公网安备 33010602011771号