广义后缀自动机模板

Posted lihior

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了广义后缀自动机模板相关的知识,希望对你有一定的参考价值。

后缀自动机能解决很多单串的问题、但是一旦到了多串的情况、可能就会变得有些棘手

这个时候你可能会想能不能将多个串一起构建出和单串后缀自动机那样子拥有诸多优美性质的自动机呢?

答案当然是有的、那就是广义后缀自动机

 

对于广义后缀自动机、和普通的后缀自动机写法上有些许不同之处

大致就是在插入新串的时候、需要把当前状态指针 last 指回 root

还有一个问题、网上的人们都说广义后缀自动机在新插入节点的时候要判是否已经存在

这个就造成了代码的迥异

 

关于代码、借鉴了这个博客 ==> Click here

 

下面仅仅给出模板

技术分享图片
struct General_Suffix_Automaton{
    static const int maxn = ((int)1e5 + 10) * 2;
    static const int Letter = 26;
    int fa[maxn];
    int len[maxn];
    int ch[maxn][Letter];
    int cnt[maxn];
    int tpSum[maxn];
    int tp[maxn];
    int tot;
    int last;
    int mxLen;

    inline void init(){
        last = tot = 1;
        len[1] = 0;
        mxLen = 0;
        memset(ch[1], 0, sizeof(ch[1]));
        memset(cnt, 0, sizeof(cnt));
    }

    inline void add(int x){
        int p = last;
        if(ch[p][x] && len[ch[p][x]] == len[p] + 1){
            last = ch[p][x];
            return ;
        }///就是在这里特判、下面的代码就基本和普通的SAM差不多了
        int np = ++tot;
        memset(ch[np], 0, sizeof(ch[np]));
        last = np;
        len[np] = len[p] + 1;
        while(p && !ch[p][x]) ch[p][x] = np, p = fa[p];
        if(!p) fa[np] = 1;
        else{
            int q = ch[p][x];
            if(len[q] == len[p] + 1) fa[np] = q;
            else{
                int nq = ++tot;
                len[nq] = len[p] + 1;
                memcpy(ch[nq], ch[q], sizeof(ch[q]));
                fa[nq] = fa[q];
                fa[q] = fa[np] = nq;
                while(p && ch[p][x] == q) ch[p][x] = nq, p = fa[p];
            }
        }
    }

    inline void addStr(char * s){
        last = 1;
        int len = strlen(s);
        mxLen = max(mxLen, len);
        for(int i=0; i<len; i++) add(s[i] - a),cnt[last]++;
    }

    int deg[maxn];
    inline void toposort(){
        for(int i = 1; i <= mxLen; i++)tpSum[i] = 0;
        for(int i = 1; i <= tot; i++)tpSum[len[i]]++;
        for(int i = 1; i <= mxLen; i++)tpSum[i] += tpSum[i-1];
        for(int i = 1; i <= tot; i++)tp[tpSum[len[i]]--] = i;
        for(int i = tot; i; i--)cnt[fa[tp[i]]] += cnt[tp[i]];
//        用下面的队列来构造拓扑序也是可以的
//        queue<int> que;
//        while(!que.empty()) que.pop();
//        int tmp = tot;
//        for(int i=1; i<=tot; i++) deg[fa[i]]++;
//        for(int i=1; i<=tot; i++) if(!deg[i]) que.push(i);
//        while(!que.empty()){
//            int x = que.front();
//            que.pop();
//            tp[tmp--] = x;
//            deg[fa[x]]--;
//            if(!deg[fa[x]]) que.push(fa[x]);
//        }
//        for(int i=tot; i>=1; i--) cnt[fa[tp[i]]] += cnt[tp[i]];
    }

    inline void GetAns(char *s){
        ///....
    }
}sam;
View Code

 

以上是关于广义后缀自动机模板的主要内容,如果未能解决你的问题,请参考以下文章

模板广义后缀自动机模板

BZOJ2806CTSC2012Cheat 广义后缀自动机+二分+Dp

bzoj 4566 找相同字符 —— 广义后缀自动机

BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机 后缀自动机 字符串

后缀自动机广义后缀自动机备忘录

POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)