AC自动机

模板:洛谷P5357

code:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int fail[N],tr[N][26],idx,n,times[N];
//end[i]表示第i个字符的结尾编号
int ed[N];
vector<int> edges[N];
void insert(int i,string &s){
    int cur=0;
    for(char &ch:s){
        int path=ch-'a';
        if(!tr[cur][path])
            tr[cur][path]=++idx;
        cur=tr[cur][path];
    }
    ed[i]=cur;
}

void dfs(int u){
    for(int &v:edges[u]){
        dfs(v);
        times[u]+=times[v];
    }
}


void init(){
    queue<int> q;
    for(int i=0;i<26;i++){
        if(tr[0][i]){
            q.push(tr[0][i]);
        }
    }
    while(q.size()){
        int u=q.front();
        q.pop();
        for(int i=0;i<26;i++){
            //存在更新fail,不存在更新直通表
            if(tr[u][i]){
                fail[tr[u][i]]=tr[fail[u]][i];
                q.push(tr[u][i]);
            }
            else{
                tr[u][i]=tr[fail[u]][i];
            }
        }
    }
}
int main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++){
        string t;
        cin>>t;
        insert(i,t);
    }
    string s;
    cin>>s;
    //初始化直通表和fail数组
    init();
    int m=s.size();
    for(int cur=0,i=0;i<m;i++){
        cur=tr[cur][s[i]-'a'];
        //增加匹配次数
        times[cur]++;
    }
    //建反图
    for(int i=1;i<=idx;i++){
        edges[fail[i]].push_back(i);
    }
    //遍历fail指针建的树
    //汇总每个节点的词频
    dfs(0);
    for(int i=1;i<=n;i++){
        cout<<times[ed[i]]<<endl;
    }
    return 0;
}
posted @ 2025-09-24 23:57  xdhking  阅读(6)  评论(0)    收藏  举报