《浅谈压缩后缀自动机》 - 学习笔记

以前对后缀数据结构的理解不够深刻,希望读完这篇论文之后可以有较为透彻的认识。

3 OI 中的传统后缀数据结构

3.1 后缀字典树

把所有后缀拎出来建字典树,然后把后缀对应的点标记为灰色。

3.2 后缀自动机

DFA 的最小化的概念:(我并没有查找资料所以只是个人理解)如果两个点连向的点对应等价,那么这两个点也等价,可以合并到一起。

比如上图中可以把 aab,abaab,baab 合并,然后把 aa,abaa,baa 合并,等等。

定义 3.2 :把后缀字典树上 \(Right\) 集合相同的节点合并,得到的 DFA 称为后缀自动机。

把除了开始状态外,出度不为 1 的点标记为灰色(注意两种标灰色的方法是不一样的)。

显然沿着后缀自动机的边 dfs 一遍可以得到原来的后缀字典树。

注意在定义中没有提到最小化的概念。事实上合并 \(Right\) 集合相同的点和最小化是类似的,但不完全相同,比如下面这个例子

可以发现,唯一的差别就是是否会把 \(Right\) 集合的对称差恰好是 \(\{|S|\}\) 的点合并,这是因为 \(|S|\) 是否出现在 \(Right\) 集合中对出边没有影响。

所以如果在最小化时强制要求灰色和白色的点不能合并,那么得到的结果就一样了。

后缀自动机有用的本质原因:两个 \(Right\) 集合要么不交,要么互相包含,所以组成了一个不超过 \(n\) 个叶子的树形结构,所以节点数在 \(O(|S|)\) 级别。

3.3 后缀树

后缀字典树的叶子个数只有至多 \(|S|\) 个,对它们建立虚树就会得到后缀树。

显然这就是把所有出度为 1 的节点缩起来。称这个过程为对后缀字典树的收缩。

注意有一些灰色点(即对应到一个后缀的点)也被缩起来了。如果是对所有代表原串后缀的点(而非仅仅是叶子)建虚树,得到的叫做完整后缀树。

4 压缩后缀自动机

4.1 定义

上面分别对后缀字典树进行了收缩和最小化操作,那么如果两个都做(先后顺序不影响),就称得到的结果为压缩后缀自动机。

或者对于完整后缀树做最小化,就得到完整压缩后缀自动机。

也就是把 \(Right\) 集合包含 \(|S|\) 的点留下来。

4.2 构造方式

显然最小化比较难做,所以考虑对后缀自动机进行收缩。

这显然可以随便做。不过怎样维护每条边上的串在原串中是哪一段呢?可以根据 \(Right\) 集合和这条边的长度得到。

完整压缩后缀自动机也类似。

4.3 性质与应用

性质 4.3.1 :各个节点在压缩后缀自动机上所有入边上的字符串是其中最长者的后缀。

性质 4.3.2 :压缩后缀自动机是后缀树最小化的结果。在压缩后缀自动机上 dfs ,可以还原出后缀树(不是后缀字典树!)。

定理 4.3 :令 \(L_i\) 表示压缩后缀自动机第 \(i\) 个节点的所有入边中最长边的长度,则 \(\sum L_i=O(|S|)\)

这是因为后缀自动机中的每条边最多贡献一次。

这与性质 4.3.1 放在一起非常强大,因为现在可以暴力处理每条边上的字符串了。(不过好像除非是题目要求,不然也没有太大用处?)

5 对称压缩后缀自动机

5.1 定义

对于同一个节点可以接收的字符串集合 \(\{T_i\}\) ,令其中最长的是 \(T_{Max}\) ,那么其他串都是 \(T_{Max}\) 的后缀(我也就是这么理解性质 4.3.1 的,不知道另一种方法是怎么样)。

并且考虑 \(Right\) 集合的定义,有

\[\forall T\in \{T_i\},LeftContext(T)=T_{Max} \]

所以也可以用 \(T_{Max}\) 来描述后缀自动机上的节点。

也就有另一种理解后缀自动机的方式:它保留了后缀字典树中 \(LeftContext(T)=T\) 的节点。

而出度为 1 ,且对应 \(Right\) 集合不包含 \(|S|\) 的节点具有唯一的出边,且不代表原串的一个后缀,所以它满足 \(RightContext(T)\ne T\) 。这样的点在构建完整压缩后缀自动机的时候被收缩了。

所以完整压缩后缀自动机的每一个点对应的 \(T\) 满足 \(Context(T)=T\) 。可以用这样的串来描述一个节点。

注意到 \(Context(T)=T\) 的子串 \(T\)\(S\) 的反串中的 \(T'\) 是一一对应的,尝试对正串和反串分别建立完整压缩后缀自动机,合并对应的节点。

同时对字符串的正反串建立完整压缩后缀自动机,将对应的节点合并,并同时保留两组转移边,称得到的结果为对称压缩后缀自动机。

绿色是正串的,表示往后添加字符;红色是反串的,表示往前添加字符(看着有点晕)。

5.2 构造方式

分别构造,然后合并。为了找到对应节点可以使用字符串哈希。

5.3 性质与应用

如果只有操作 1 那就直接普通后缀自动机即可。有操作 2 似乎也可以?

建出对称压缩后缀自动机,用 \(Context(T)\) 对应的节点表示 \(T\) ,并维护 \(T\)\(Context(T)\) 中的出现位置(显然是唯一的,不然可以一路往左推)。

然后在对称压缩后缀自动机里面跳即可。

先考虑怎么判断一个串是否是必胜态。注意到对于 \(LeftContext(T)\ne T,RightContext(T)\ne T\) 的子串 \(T\) ,它的下一步是确定的,所以只需要考虑至少满足一个的串即可。由定理 4.3 ,这样的串只有 \(O(|S|)\) 个(也就是正反 SAM 的节点对应的最长串),可以暴力 DP 。

字典序只需要随便 dfs 一下即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章