(模板)AC自动机模板

1. 给出模式串和文本串,文本串长度小于1e6,模式串长度之和小于1e6,求文本串中有多少模式串出现。

题目链接:https://www.luogu.org/problem/P3808

AC code:

/*
    luoguP3808 (AC自动机模板题)
    求文本串中有多少模式串出现
*/
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;

const int maxn=1e6+5;
struct Tree{          //Trie树
    int fail,vis[30],key; //key用来记录有几个单词以这个节点结尾
}AC[maxn];
int n,cnt;
char s[maxn];
//在Trie树中插入结点
void build(char *s){
    int len=strlen(s),u=0;
    for(int i=0;i<len;++i){
        int t=s[i]-'a';
        if(!AC[u].vis[t])
            AC[u].vis[t]=++cnt;
        u=AC[u].vis[t];
    }
    AC[u].key+=1;
}
//构建fail指针
void get_fail(){
    queue<int> que;
    for(int i=0;i<26;++i){  //提前处理第二层
        if(AC[0].vis[i]){
            AC[AC[0].vis[i]].fail=0;  //指向根节点
            que.push(AC[0].vis[i]);
        }
    }
    while(!que.empty()){    //bfs求所有子结点
        int u=que.front();
        que.pop();
        for(int i=0;i<26;++i){
            if(AC[u].vis[i]){
                AC[AC[u].vis[i]].fail=AC[AC[u].fail].vis[i];
                que.push(AC[u].vis[i]);
            }
            else{
                AC[u].vis[i]=AC[AC[u].fail].vis[i];
            }
        }
    }
}
//AC自动机匹配
int query(char *s){
    int len=strlen(s),u=0,ans=0;
    for(int i=0;i<len;++i){
        int t=s[i]-'a';
        u=AC[u].vis[t];
        for(int j=u;j&&AC[j].key!=-1;j=AC[j].fail){ //循环求解
            ans+=AC[j].key;
            AC[j].key=-1;
        }
    }
    return ans;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%s",s);
        build(s);
    }
    AC[0].fail=0;   //结束标志
    get_fail();     //求失配指针
    scanf("%s",s);
    printf("%d\n",query(s));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/FrankChen831X/p/11875749.html