题解 P3796 【【模板】AC自动机(加强版)】

· · 题解

AC自动机是结合了KMP的失配指针和TRIE的树形结构的一种算法。

(所以我们要把KMP和TRIE先搞明白)

就是能自动AC的机器

AC自动机有三个部分,分别是建树,获取失配指针和查询。

先建一棵TRIE树,再把TRIE树上每个节点的失配指针(重点中的重点)求出,最后查询文本。

首先 我们需要定义一些需要用的数组。

     int num[300010];//结点编号
     int ch[300010][26];//子结点
     int fail[300010];//失配指针
     int ans[300010];//答案
    void insert(string s,int v){
        int now=0;//当前访问的节点
        for(int i=0;i<s.size();i++){
            int o=s[i]-'a';
            if(!ch[now][o])ch[now][o]=++siz;//新编号
            now=ch[now][o];//继续访问
        }
        num[now]=v;//标记
    }

这里还有非常重要的一个细节:若fail[a]=b,则root到a的链一定包含root到b的链。

查询

这是一个与KMP最相似的部分。

假设我们要查询s,现在访问到s[i],s[i]在TRIE树上的编号为now。我们只需定义j=now,然后j不停的fail,期间ans[num[j]]++,答案就出来了。

这些都是基于我刚刚所讲的一个细节。如果root到a的链存在与s,则root到fail[a]的链也存在于s。

这样子的话,所有困难都迎刃而解。

void query(string s){
        int now=0;//当前访问节点
        for(int i=0;i<s.size();i++){
            now=ch[now][s[i]-'a'];//更新节点
            for(int j=now;j;j=fail[j])ans[val[j]]++;//进行答案累计
        }
    }