浅谈后缀自动机SAM

之前学过,但是一直半懂不懂,只会背板子
现在甚至连板子都不会背了
还是从新学一遍比较好


endpos

定义一个子串 e n d p o s endpos endpos为它在原串中结束位置集合

原串: a b a b c b ababcb ababcb
e n d p o s ( a b ) = { 2 , 4 } , e n d p o s ( b ) = { 2 , 4 , 6 } endpos(ab) = \{2,4\},endpos(b)=\{2,4,6\} endpos(ab)={2,4},endpos(b)={2,4,6}
e n d p o s endpos endpos相同的子串称为一个

有几个显然的性质

  • 如果一个子串 a a a e n d p o s endpos endpos包含子串 b b b的,那么 a a a一定是 b b b的后缀
  • 如果两个子串的 e n d p o s endpos endpos有交,那么一定是一个包含另一个,且子串是后缀关系
  • 对于一个,设最大长度为 m a x max max,最小的为 m i n min min,那么长度在 [ m i n , m a x ] [min,max] [min,max]中的都存在

parent tree(后缀link)

根据 e n d p o s endpos endpos的子集关系建一颗树
在这里插入图片描述

可以发现这棵树正好能满足SAM的所有性质,就很虚浮
点边都是 O ( n ) O(n) O(n)

同样可以得到一个重要的性质

  • 假设 m i n ( x ) , m a x ( x ) min(x),max(x) min(x),max(x)表示这个类能表示的最短/长子串长度,可以得到 m i n ( x ) = m a x ( f a ) + 1 min(x)=max(fa)+1 min(x)=max(fa)+1
    挺显然的

把上面绿色的节点称做终止链

构造

可结合图片&代码来理解

在这里插入图片描述
结构体的部分本别表示转移边,最大长度和后缀link

struct A {
    int ch[27], len, fa;
} a[N << 2];
int lst = 1, tot = 1, n;
void insert(int c, int id) {
    int p = lst, np = ++ tot; lst = np;
    a[np].len = a[p].len + 1;//接上终止链
    while(p && !a[p].ch[c]) a[p].ch[c] = np, p = a[p].fa;//把终止链上的转移边加上
    if(!p) a[np].fa = 1;
    else {
        int q = a[p].ch[c];//找到第一个可以转移的,考虑np和它合并
        if(a[q].len == a[p].len + 1) a[np].fa = q;//如果中间没有其他串,那后缀link指向它
        else {
            int clone = ++ tot; a[clone] = a[q];//不然就把这个类拆开成两部分
            a[clone].len = a[p].len + 1;
            while(p && a[p].ch[c] == q) a[p].ch[c] = clone, p = a[p].fa;//把信息继承过来
            a[np].fa = a[q].fa = clone;
        }
    }
}

大概就这样,具体用法多做题即可
有时间再补

posted @ 2021-09-08 08:15  lahlah  阅读(40)  评论(0编辑  收藏  举报