「ROI 2019 Day2」模式串查找 (口胡)

「ROI 2019 Day2」模式串查找 (口胡)

\(S=\sum |w_i|\)

显然我们需要一个树形数据结构来维护题目中添加字符的操作

归纳一下,需要实现的操作就是:

1.添加一个新串

2.在当前串中分裂一段区间 \([L,R]\)

3.将一个串复制 \(k\)

将每一个单字符视为一个节点,考虑用一个可持久化的平衡树来维护上述操作,比如可持久化非旋 \(\text{Treap}\)

题解中给出的2-3-Tree不知道效果怎么样

2,3操作增加的数量为 \(\log\) 级别,最终的节点总数为 \(O(S+n\log S)\)

接下来需要实现的操作是合并两个子串的信息,显然在合并时计算跨过两个节点的串匹配模板串的次数

容易想到记录后缀匹配的 \(kmp\) 指针,但是这样的指针难以完成合并操作

为了计算这个,我们需要维护这个串的前缀/后缀 在 原串上最长的匹配子段

此时一个节点的信息可以用 \((l1,r1),(l2,r2),k\) 来表示,其中 \(k\) 标记了这个串是否整个出现在模板串中

合并子串 \(A,B\) 信息:

1.求出前缀/后缀匹配,以前缀为例:

1-1.如果 \(A\) 无法完全匹配,则匹配前缀为 \(A\) 的匹配前缀

1-2. \(A\) 能够完全匹配,设 \(A\) 在原串对应 \(L,R\)\(B\) 的最长匹配前缀在模板串匹配起始位置为 \(P\)

我们需要在 \([L,R]\) 之后借上 \(P\) 开始的一段后缀,而 \([L,R]\) 出现在模板串中的位置对应着后缀数组上一段 \(rank\) 区间

取模板串反向后缀数组,求出与 \(R\) 匹配长度超过 \(R-L+1\)\(rank\) 区间 \([l,r]\)

则我们需要找到 \([l,r]\)\(sa[i]+1\)\(P\) 最长的 \(LCP\) ,显然是一个求临近 \(rank\) 的问题,可以在线主席树二分解决

由此得到最长前缀为 \(A\) 串再加上额外匹配得到的部分

\(O(\log m)\) 完成

\[ \ \]

2.求出跨过两个串的完美匹配个数

容易得到前串后缀对应的 \(\text{kmp}\) 指针,后串前缀对应反向的 \(\text{kmp}\) 指针

实际上就是求出这两个指针不断失配时相加恰好完全匹配的个数

注意到,实际上这个询问是完全可以离线

可以通过在线得到的匹配情况,离线得到询问得到询问答案,再从叶子开始重新计算每个节点的答案

比较暴力的做法是:

建立两棵 \(\text{kmp}\) 树,在第一棵树上 \(\text{dfs}\) ,加入祖先对应的位置,然后再第二棵树上查询祖先匹配的个数

可以用 \(\text{dfs}\) 序+差分树状数组维护,复杂度为 \(O(\log m)\)

\[ \ \]

因此总体复杂度为 \(O((S+n\log S)\log m)\) 实际上常数非常大?