BZOJ.2780.[SPOJ8093]Sevenk Love Oimaster(廣義後綴自動機)

題目連接php

\(Description\)

給定n個模式串,屢次詢問一個串在多少個模式串中出現過。(字符集爲26個小寫字母)html

\(Solution\)

對每一個詢問串進行匹配最終會達到一個節點,咱們須要獲得這個節點所表明的子串出如今多少個模式串中。
創建廣義後綴自動機。每次插入一個串,從root開始,對於SAM上每一個節點維護cnt和bef,分別表示該節點表明的串出如今幾個模式串中 和 該節點最近被哪一個模式串更新過cnt。
對於bef[i]!=now的節點,++cnt[i],bef[i]=now;當模式串now下次匹配到當前節點時則再也不更新。
另外,若是匹配了當前節點i那麼必定會匹配上fa[i],fa[fa[i]]...若是它們的bef[]!=now,則都更新一遍。直到有個節點p知足bef[p]==now,那麼就不須要再向上更新了(再往上已經更新過了)。(這個在insert後用np更新就能夠啊)數組

這個暴力跳的複雜度多是\(O(n\sqrt n)\)的,可是很難卡滿(廣義SAM上一個點暴力跳fa的次數是\(O(\sqrt n)\)的,具體見這裏)。
有一種離線+DFS序+樹狀數組的作法能夠作到\(\log n\)。(注意廣義SAM應該要像這題那麼建)
但事實上這題還有個剪枝(bef[np]==now),廣義SAM上狀況比較複雜我也不知道真正的複雜度是啥。。ui

注意新建nq時 bef[nq],cnt[nq]也要複製(=...[q])。spa

//24612kb   76ms
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gc() getchar()
const int N=2e5+5;

struct Suffix_Automaton
{
    int las,tot,fa[N],son[N][26],len[N],cnt[N],bef[N];
    char s[360005];

    void Init(){
        las=tot=1;
    }
    void Insert(int now,int c)
    {
        int p=las,np=++tot; len[las=np]=len[p]+1;
        for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
        if(!p) fa[np]=1;
        else
        {
            int q=son[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else
            {
                int nq=++tot;
                len[nq]=len[p]+1, bef[nq]=bef[q], cnt[nq]=cnt[q];//!
                memcpy(son[nq],son[q],sizeof son[q]);
                fa[nq]=fa[q], fa[q]=fa[np]=nq;
                for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
            }
        }
        for(; bef[np]!=now&&np; np=fa[np])
            ++cnt[np], bef[np]=now;
    }
    void Build(int now)
    {
        las=1, scanf("%s",s);
        for(int i=0,l=strlen(s); i<l; ++i)
            Insert(now,s[i]-'a');
    }
    void Query()
    {
        int p=1; scanf("%s",s);
        for(int i=0,l=strlen(s); i<l&&p; ++i)
            p=son[p][s[i]-'a'];
        printf("%d\n",cnt[p]);
    }
}sam;

int main()
{
    int n,Q; scanf("%d%d",&n,&Q); sam.Init();
    for(int i=1; i<=n; ++i) sam.Build(i);
    while(Q--) sam.Query();

    return 0;
}
相關文章
相關標籤/搜索