回文树 PAM 学习笔记

摘自 《2017 年国家集训队论文》“ 回文树及其应用 ”

  • 一些规定 : Σ \Sigma Σ 表示字符集大小
    S S S 和字符 c c c,用 S c Sc Sc 表示将 c c c 接在 S S S 的后面

  • 回文树:回文树是一棵由两棵树组成的森林,两棵树的根分别为 o d d , e v e n odd,even odd,even,回文树上的除根以外的一个结点表示一个字符串,每条边有一个字符, l e n len len 表示一个结点代表的字符串的长度,一个结点代表的字符串可以由如下方式得到:
    从根开始沿着路径走,走过一条边就将边上的字母添加到两边,即 T → c T c T\to cTc TcTc,其中从 o d d odd odd 出发的第一步只添加一个字符
    f a i l fail fail 表示一个结点的失配指针,一个成型的回文树如下:
    在这里插入图片描述

  • 容易注意到,一个长为 ∣ S ∣ |S| S 的字符串的 P A M PAM PAM 结点数为 ∣ S ∣ + 2 |S|+2 S+2,要证明这点,我们只需要证明一个长为 ∣ S ∣ |S| S 的串的本质不同子串数为 ∣ S ∣ |S| S,考虑数学归纳法:
    ∣ S ∣ = 1 |S|=1 S=1 时成立
    ∣ S ∣ > 1 |S|>1 S>1 时假设 S = S ′ c S=S'c S=Sc,考虑 c c c 与前面的串形成的新的回文后缀,不妨设这些右端点为 l 1 , l 2 , … , l k l_1,l_2,\dots,l_k l1,l2,,lk,若右端点为空集,那么 c c c 自成回文串,否则注意到若 S [ l 1 . . ∣ S ∣ ] , S [ l k . . ∣ S ∣ ] S[l_1..|S|],S[l_k..|S|] S[l1..S],S[lk..S] 是一个回文串的话,那么 S [ l 1 . . l 1 + ∣ S ∣ − l k + 1 ] S[l_1..l_1+|S|-l_k+1] S[l1..l1+Slk+1] 也为一个回文串,而 l 1 + ∣ S ∣ − l k + 1 ≤ ∣ S ∣ − 1 l_1+|S|-l_k+1\le |S|-1 l1+Slk+1S1 是之前出现过的,故一个末尾字符新产生的不同回文串只有一个,这是它的最长回文后缀

  • 构造方法:
    我们需要对每个串 S c Sc Sc 找到它的最长回文后缀,对此,我们在 S S S 代表的串的最长后缀的 f a i l fail fail 链上找一个最长的串 T T T,满足 S [ ∣ S ∣ − l e n t ] = c S[|S|-len_t]=c S[Slent]=c,那么 S c Sc Sc 代表的回文串为 c T c cTc cTc,我们新建一个结点表示这个点后,还需要求出它的 f a i l fail fail,这一步相当于在 f a i l T fail_T failT 的链上求一个最长的串 v v v 满足 S [ ∣ S ∣ − l e n v ] = c S[|S|-len_v]=c S[Slenv]=c

  • 复杂度分析:空间复杂度 O ( ∣ S ∣ ) O(|S|) O(S),时间复杂度 O ( ∣ S ∣ log ⁡ Σ ) O(|S|\log \Sigma) O(SlogΣ)
    考虑势能分析跳 f a i l fail fail 树的这一步,一是找最长回文后缀的贡献,一是找 f a i l fail fail 的贡献,二者是同阶的,我们分析前者,假设最长回文后缀为 l e n i len_i leni,那么有 l e n i + 1 ≤ l e n i + 1 len_{i+1}\le len_i+1 leni+1leni+1,故只会增长 n n n 次,所以一共会跳至多 n n n f a i l fail fail,在 f a i l fail fail 处检查 c c c 是否存在,花费 log ⁡ Σ \log \Sigma logΣ 的代价
    当然也可以变成 O ( ∣ S ∣ Σ ) + O ( ∣ S ∣ ) O(|S|\Sigma)+O(|S|) O(SΣ)+O(S)

  • ∣ r i g h t ∣ |right| right 集合,即 f a i l fail fail 树中子树右端点的点集,性质与 S A M SAM SAM 一样,表示出现次数

  • 前端插入:
    对此,我们需要维护 f a i l ′ fail' fail 来寻找最长回文前缀,而注意到每个串都是回文串的性质,发现有 f a i l ′ = f a i l fail'=fail fail=fail 的性质

  • 不基于势能分析的插入方法:
    我们对一个结点 t t t 维护 q u i c k ( c ) quick(c) quick(c) 表示 t t t 最长的满足前驱为 c c c 的回文后缀
    注意到 t t t q u i c k quick quick f a i l t fail_t failt q u i c k quick quick 没有什么区别,我们将 f a i l t fail_t failt q u i c k quick quick 复制给 t t t
    c c c f a i l t fail_t failt 的前驱,后用 f a i l t fail_t failt 来更新 t t t q u i c k ( c ) quick(c) quick(c) 即可
    t r i e trie trie 树上建 P A M PAM PAM 就需要不基于势能分析的插入方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值