码迷,mamicode.com
首页 > 其他好文 > 详细

广义后缀自动机模板

时间:2018-11-10 21:12:47      阅读:552      评论:0      收藏:0      [点我收藏+]

标签:HERE   queue   情况   close   pen   基本   last   logs   emc   

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

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

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

 

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

大致就是在插入新串的时候、需要把当前状态指针 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

 

广义后缀自动机模板

标签:HERE   queue   情况   close   pen   基本   last   logs   emc   

原文地址:https://www.cnblogs.com/LiHior/p/9940403.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!