#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <algorithm>
#define N 500006
using namespace std;
char st[1000005];
char keyword[55];
int n,m;
int next[N][26],cnt[N],fail[N],pos;
//初始化字典树的节点
int newNode ( )
{
for ( int i = 0; i < 26 ; i++ ) next[pos][i] = 0;
fail[pos] = cnt[pos] = 0;
return pos++;
}
//构建字典树
void insert ( char *s )
{
int i,p = 0;//p当前为根节点,i为字符串初始位置
for ( i = 0 ; s[i] ; i++ )
{
//获得这一字母的节点,如果不存在,创建新的
int k = s[i] -'a' , &x = next[p][k];
p = x?x : x = newnode();
}
cnt[p]++; // 位运算要用
}
//通过宽搜构建失败指针
void makeNext ( )
{
int i;
queue<int> q;
q.push(0); // 将根节点放入队列中
while ( !q.empty() )
{
int u = q.front();
//统计匹配到当前位置能够匹配到的串的个数
cnt[u] += cnt[fail[u]];
q.pop ();
for ( int i = 0 ; i < 26 ; i++ )
{
int v = next[u][i];
//如果v是0,证明不能匹配,所以通过fail指针找到深度小于当前深度但
//是深度最大的与v和自身的最近公共祖先相邻的与v具有相同字母的节点
//需要通过fail指针跳转过去
if ( v == 0 ) next[u][i] = next[fail[u]][i];
else q.push (v);
//否则,要将v推到队列中去,用于宽搜
if ( u && v )
fail[v] = next[fail[u]][i];
}
}
}
int query ( char *s )
{
int ret = 0, idx , d = 0;
for ( int i = 0; s[i]; i++ )
{
idx = s[i] -'a';
d = next[d][idx];
//将当前位置作为串的结尾能匹配到的串的个数
ret += cnt[d];
//将串的个数清0,避免重复统计
cnt[d] = 0;
}
return ret;
}
AC自动机模板
最新推荐文章于 2019-03-10 16:17:00 发布