广义后缀自动机模板

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

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

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

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

大致就是在插入新串的时候、需要把当前状态指针 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
原文地址:https://www.cnblogs.com/qwertiLH/p/9940403.html