首先要注意到一个简单的性质:S,T 相似等价于 LCP(S,T)+LCS(S,T)≥m−1,其中 LCP,LCS 分别为最长公共前缀和后缀。
设 S,T 分别从原串的第 s,t 个字符起始,则条件即为 LCP(s−m+1,t−m+1)+LCS(s,t)≥m−1,其中 LCP,LCS 分别为两个后缀的最长公共前缀和两个前缀的最长公共后缀。
利用 SAM 建出前缀树和后缀树,考虑在前缀树上静态链分治确定 LCA。
对于当前处于不同子树内的前缀 i,j,设 len 为当前 LCA 包含状态的最长长度。
则易知需满足 LCS(i−m+1,j−m+1)≥m−len−1。
也即后缀 i−m+1,j−m+1 在后缀树上的 LCA 的长度不小于 m−len−1。
考虑枚举 i,在后缀树上倍增求出后缀 i−m+1 的最浅的满足长度不小于 m−len−1 的祖先,则合法的 j−m+1 一定也在其子树内。
也就是要求出当前已经处理过的子树中存在的前缀和后缀树上某个子树内的交集。
考虑用一个树状数组维护即可。
(当然你硬要拿二维数点搞我也不拦你)
但是这样只能把 j 的贡献计算到 i 上,而且链分治是必须按照一定顺序处理的,所以还要考虑如何把 i 的贡献计算到 j 上。
考虑用一个全局的树状数组维护 i 对 j 的贡献。
注意会有错算的贡献,要容斥掉。
(话说怀疑全世界只有我一个在后缀树上链分治的时候直接用 vector 维护 endpos 虽然这样好写点不用再去递归搜一遍)
代码:
1 |
|