1. 程式人生 > >廣義字尾自動機模板

廣義字尾自動機模板

字尾自動機能解決很多單串的問題、但是一旦到了多串的情況、可能就會變得有些棘手

這個時候你可能會想能不能將多個串一起構建出和單串字尾自動機那樣子擁有諸多優美性質的自動機呢?

答案當然是有的、那就是廣義字尾自動機

 

對於廣義字尾自動機、和普通的字尾自動機寫法上有些許不同之處

大致就是在插入新串的時候、需要把當前狀態指標 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