「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)\) 实际上常数非常大?