AC自动机模板 (模板题 bzoj 4327)

题目:这里写链接内容
可持久化版本待续
此题删掉trans数组,否则会MLE

//AC自动机
//功能,一堆串和一个串进行匹配,看哪些位置可以被匹配。
//fail指针。当前串最长的后缀等于某个节点所表示的前缀。
//fail树。fail指针所形成的树。fail树上的所有祖先都是该节点的子串
//常见套路:
//记录节点状态(当前匹配到哪个节点),DP,快速幂优化
//利用所有后缀的前缀是所有子串的性质
//直接利用fail树和tried树的性质 如本题 bzoj 4327
//可持久化AC自动机。字符集1e5.用可持久化线段树维护fail
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn 10001020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8


typedef long long ll;

struct node{
    int next,to;
}e[maxn];
int head[maxn],cnt;
int n,m;
int nxt[maxn][4],tot,cur,fail[maxn],len[maxn];
int trans[maxn][4];
bool vis[maxn];
int tag[100020];
int q[maxn],hh,tt;
int mp[200];
char ch[maxn],s[maxn];

inline void insert(int x){ //将模板串插入trie树
    if ( !nxt[cur][x] ) nxt[cur][x] = ++tot;
    cur = nxt[cur][x];
}
inline void adde(int x,int y){ //加边
    e[++cnt].to = y;
    e[cnt].next = head[x];
    head[x] = cnt;
}
void build(){ //建立AC自动机,求fail数组
    rep(i,0,3) if ( nxt[0][i] ) q[tt++] = nxt[0][i];
    while ( hh < tt ){
        int x = q[hh++];
        rep(i,0,3){
            if ( nxt[x][i] ){
                int p = nxt[x][i],f = fail[x];
                while ( f && !nxt[f][i] ) f = fail[f]; //如果没有出边,则继续跳fail
                fail[p] = nxt[f][i];
                q[tt++] = p; //别忘了把当前点加入队列
            }
        }
    }
    rep(i,1,tot) adde(fail[i],i);
    rep(i,1,tot){ //建立trie图
        rep(j,0,3){
            int p = i;
            while ( p && !nxt[p][j] ) p = fail[p];
            trans[i][j] = nxt[p][j];
        }
    }
}
void dfs(int x){ //dfs fail树
    for (int i = head[x] ; i ; i = e[i].next){
        dfs(e[i].to);
        vis[x] |= vis[e[i].to];
    }
}
void dfs(int x,int key,int dth){ //dfs trie树
    if ( vis[x] ) key = dth;
    len[x] = key;
    rep(i,0,3) if ( nxt[x][i] ) dfs(nxt[x][i],key,dth + 1);
}
void solve(){
    cur = 0;
    rep(i,0,n - 1){ //匹配母串
        while ( cur && !nxt[cur][mp[s[i]]] ) cur = fail[cur];
        cur = nxt[cur][mp[s[i]]] , vis[cur] = 1;
    }
    dfs(0);
    dfs(0,0,0);
    rep(i,1,m) printf("%d\n",len[tag[i]]);
}
int main(){
    mp['E'] = 0 , mp['S'] = 1 , mp['W'] = 2 , mp['N'] = 3;
    scanf("%d %d",&n,&m);
    scanf("%s",s);
    rep(i,1,m){
        scanf("%s",ch);
        int l = strlen(ch); cur = 0;
        rep(j,0,l - 1) insert(mp[ch[j]]);
        tag[i] = cur; //记录当前串插入到哪个节点。注意,每个节点可能对应多个串,反过来记要开vector
    }
    build();
    solve();
    return 0;
}




猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/81486601
今日推荐