AC自动机

↘锁芯ラ 提交于 2019-12-05 15:30:07

P5357 【模板】AC自动机(二次加强版)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
const int M=2e6+7;
char s[N],S[M];
int cnt,tot,to[N],ans[N],du[N];
struct node{
    int fail,end,ch[27];
}t[N];
inline void insert(char *str){
    int now=0;
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(!t[now].ch[str[i]-'a'+1])
            t[now].ch[str[i]-'a'+1]=++cnt;
        now=t[now].ch[str[i]-'a'+1];//构造 trie 树
    }
    ++tot;
    if(t[now].end) to[tot]=t[now].end;
    if(!t[now].end) t[now].end=tot;
}
queue <int> q;
int num[N];
void build(){
    for(int i=1;i<=26;i++)
        if(t[0].ch[i]){
            t[t[0].ch[i]].fail=0;
            q.push(t[0].ch[i]);
        }
    while(q.size()){//bfs 求出失配指针,指向的其实就是他的最大真后缀
        int now=q.front();
        q.pop();
        for(int i=1;i<=26;i++){
            if(t[now].ch[i]){
                t[t[now].ch[i]].fail=t[t[now].fail].ch[i];
                q.push(t[now].ch[i]);
                du[t[t[now].ch[i]].fail]++;
            }
            else t[now].ch[i]=t[t[now].fail].ch[i];
        }
    }
}
void query(char *str){
    int now=0;
    int len=strlen(str);
    for(int i=0;i<len;i++){
        now=t[now].ch[str[i]-'a'+1];
        num[now]++;
    }
}
void topu(){
    for(int i=1;i<=cnt;i++)//复杂度正确的 trie 树使用方式
        if(!du[i]) q.push(i);
    while(q.size()){
        int now=q.front();
        q.pop();
        ans[t[now].end]=num[now];
        num[t[now].fail]+=num[now];
        if(!(--du[t[now].fail])) q.push(t[now].fail);
    }
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert(s);
    }
    build();
    scanf("%s",S);
    query(S);
    topu();
    for(int i=1;i<=n;i++){
        if(!to[i]) printf("%d\n",ans[i]);
        else printf("%d\n",ans[to[i]]);
    }
    return 0;
}

P3966 [TJOI2013]单词

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
char s[N];
int cnt,tot,to[N],num,du[N];
int sz[N],pos[N];
struct node{
    int fail,end,ch[27];
}t[N];
inline void insert(char *str){
    int now=0;
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(!t[now].ch[str[i]-'a'+1])
            t[now].ch[str[i]-'a'+1]=++cnt;
        now=t[now].ch[str[i]-'a'+1];
        sz[now]++;
    }
    ++tot;//看对于AC自动机建出来的trie图的理解
    pos[tot]=now;
}
queue <int> q;
void build(){
    for(int i=1;i<=26;i++)
        if(t[0].ch[i]){
            t[t[0].ch[i]].fail=0;
            q.push(t[0].ch[i]);
        }
    while(q.size()){
        int now=q.front();
        q.pop();
        du[++num]=now;
        for(int i=1;i<=26;i++){
            if(t[now].ch[i]){
                t[t[now].ch[i]].fail=t[t[now].fail].ch[i];
                q.push(t[now].ch[i]);
            }
            else t[now].ch[i]=t[t[now].fail].ch[i];
        }
    }
}
int n;
void query(){
    for(int i=cnt;i>=0;i--) sz[t[du[i]].fail]+=sz[du[i]];//这里按照bfs的顺序更新的,如果把A作为fail的点B有贡献的话,A作为B的最大后缀也一定有贡献,所以可以这样处理
    for(int i=1;i<=n;i++) printf("%d\n",sz[pos[i]]);
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert(s);
    }
    build();
    query();
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!