Border 的四种求法
感觉都挺好玩的。
不会都写。会都不写。
Border 论做法
border 可以被划分成 log 个等差数列。配合 dbf 表等性质可以存储下整个子串的 border。
复杂度 \(O(n\log n)\),是最优的做法。不建议在没对 SA 和 border 论有充分理解的情况下使用。
链分治做法
基于 parent tree。
你需要两种刻画方式。
第一个方式是 border 是前缀的后缀。于是从 r 开始往上跳,找 endpos 集合内的值。
第二个方式是 border 相当于取一个 \([l,r)\) 内的前缀使得最长公共后缀不比前面部分小。
最长公共后缀这种东西容易想到就是 parent tree 上的 lca。
于是从根向 r dfs,统计其余子树的贡献。容易想到提前预处理出来。
虽然两个方式复杂度都不对但是一个是现求一个是预处理不是感觉很能平衡吗?
链分治,r 向上跳的过程中除了轻边上的重儿子,其它的结点都是遍历自己的轻子树。轻子树和是 \(O(n\log n)\) 的,可以预处理。
轻边上的重儿子只有 \(\log n\) 个,使用方式一即可。
这种做法的另一种实现是点分治。
DAG 链剖分
开始大炮打蚊子。
类似树剖,任意一条路径轻边数量可以保证。
令 \(f_i\) 为以 \(i\) 为终点的路径数,\(g_i\) 为以 \(i\) 为起点的路径数。\((u,v)\) 是重边当且仅当 \(u\) 是 \(v\) 入点中 \(f\) 最大的,\(v\) 是 \(u\) 出点中 \(g\) 最大的。
不难证明剖出来的是链。并且每次 \(f\) 或 \(g\) 其中一定会有一个减半,所以只有 \(\log V\) 条轻边。\(V\) 为路径条数。
这个除了 SAM 还真不知道有什么用的到。
border 的一种刻画方式:\([1,r]\) 的所有后缀与 \([l,n]\) 的所有前缀的交。前者跳 parent tree 的祖先链,后者即 SAM 上一条到 \(l\) 的链。
基本子串结构
当然也可以看原抡文。核武器轰草履虫。应该是这里面最泛用的解法。
根号分治
四种求法有五个很正常吧。
border 小的时候可以 hash check,大的时候考虑本质不同的 border 不会很多。
暂咕。

浙公网安备 33010602011771号