SAM学习总结

学习blog: 史上最通俗的后缀自动机详解

(文章长度一个小时,上文作者学了两天,本蒟蒻学了三个星期 QwQ )

先定义:

  • 本质相同的子串:

    在原串中除了位置不同,字符串本身完全相同的子串

  • endpos

    本质相同的一类子串的右端点集合
    性质:本质相同的一类子串对应一个右端点集合,一个右端点集合可能对应多类(本质互不相同的)本质相同的子串类

    SAM的精髓,就在于先把所有本质相同的子串合并成若干子串类,再把endpos相同的子串类合并成若干个endpos类,合并了大量有效信息

  • 结点:

    SAM的每个结点对应一个endpos等价类,也就是一个子串集合
    性质:对每个结点对应的子串集合本质相同的去重,剩下的子串在原串中是连续的一段

  • 转移边:

    SAM的转移边标有字符,从一个节点指向另一个节点,表示该结点对应的去重
    子串集合尾部加上该字符可以变成下一个endpos等价类

  • 父向边:

    SAM每个结点有一条父向边,表示该类后缀中最长的,与该类endpos集合不等价
    的子串所在的endpos集合

  • 长度:

    SAM每个结点有一个长度值,表示该endpos等价类中最长子串长度

    构造代码:

    struct SAM{
    int ch[N][26],fa[N],len[N],tot,las;
    int& operator [](const int& x){return len[x];}
    void ins(int c){
    int p=(las?las:n+1),np=++las;for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
    if(!p){fa[np]=n+1;return;}int q=ch[p][c];
    if(len[q]len[p]+1){fa[np]=q;return;}int nq=++tot;
    len[nq]=len[p]+1;fa[nq]=fa[q];For(i,0,25)ch[nq][i]=ch[q][i];
    for(;p&&ch[p][c]
    q;p=fa[p])ch[p][c]=nq;fa[q]=fa[np]=nq;
    }
    void build(){
    scanf("%s",s+1);n=strlen(s+1);tot=n+1;las=0;
    For(i,1,n)len[i]=i;For(i,1,n)ins(s[i]-'a');
    }
    };
    //这样构造的话,SAM结点编号与前缀右端点位置就直接对应了

  • posted @ 2021-07-11 10:56  Sherlockk  阅读(122)  评论(0)    收藏  举报