AC自动机

构建字典图实现自动跳转,构建失配指针实现多模式匹配

\(\text{fail}\) 指针表示文本串在当前节点失配后,我们应该到哪个节点去继续匹配,\(u\)\(\text{fail}\) 指针指向 \(v\) 表示从根到 \(v\) 的字符串为从根到\(u\)的字符串的最长后缀,用 \(\text{bfs}\) 来构建 \(\text{fail}\) 指针

\(fail[trie[x][i]]=trie[fail[x]][i]\)

相当于在 \(x\)\(fail[x]\) 后面加一个字符 \(i\),就构成 \(fail[trie[x][i]]\)

若发现 \(trie[x][i]\) 不存在,则直接将其 \(trie[fail[x]][i]\) 赋值给它,来实现一个类似于路径压缩的操作

void insert(char *str)
{
    int len=strlen(str+1),p=root;
    for(int i=1;i<=len;++i)
    {
        int ch=str[i]-'a';
        if(!trie[p][ch]) trie[p][ch]=++tot;
        p=trie[p][ch];
    }
    num[p]++;
}
void build()
{
    queue<int> q;
    for(int i=0;i<26;++i)
        if(trie[root][i])
            q.push(trie[root][i]);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<26;++i)
        {
            int y=trie[x][i];
            if(y) fail[y]=trie[fail[x]][i],q.push(y);
			else trie[x][i]=trie[fail[x]][i];
        }
    }
}
int query(char *str)
{
    int len=strlen(str+1),p=root,ans=0;
    for(int i=1;i<=len;++i)
    {
        int ch=str[i]-'a';
        p=trie[p][ch];
        for(int j=p;j&&num[j]!=-1;j=fail[j])
            ans+=num[j],num[j]=-1;
    }
    return ans;
}
posted @ 2020-01-22 20:21  lhm_liu  阅读(132)  评论(0)    收藏  举报