有 N 个单词组成了一篇文章,求每个单词在这篇文章中出现了多少次。
多个字符串匹配的问题,建立AC自动机。如果某个单词在 i 节点出现了,那么在 i 节点 fail 指针所指节点也出现过。
CODE:
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX_N = 1000005;
struct Trie {
int ch[26], fl, sum;
} t[MAX_N];
int n, sz, pos[205];
char s[MAX_N];
int insert()
{
int u = 0, l = strlen(s + 1);
for (int i = 1; i <= l; i ++) {
int c = s[i] - 'a';
if (!t[u].ch[c]) t[u].ch[c] = ++ sz;
u = t[u].ch[c];
t[u].sum ++;
}
return u;
}
void init()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
scanf("%s", s + 1),
pos[i] = insert();
}
int q[MAX_N], vec[MAX_N], tot = 0;
void get_Fail()
{
int hd = 0, tl = 0;
t[0].fl = 0;
for (int c = 0; c < 26; c ++)
if (t[0].ch[c]) {
t[t[0].ch[c]].fl = 0;
q[++ tl] = t[0].ch[c];
}
while (hd < tl) {
int r = q[++ hd]; vec[++ tot] = r;
for (int c = 0; c < 26; c ++) {
if (!t[r].ch[c]) {
t[r].ch[c] = t[t[r].fl].ch[c];
continue;
}
q[++ tl] = t[r].ch[c];
int u = t[r].ch[c], v = t[r].fl;
while (v && !t[v].ch[c]) v = t[v].fl;
t[u].fl = t[v].ch[c];
}
}
for (int i = tot; i >= 0; i --)
t[t[q[i]].fl].sum += t[q[i]].sum;
}
void doit()
{
get_Fail();
for (int i = 1; i <= n; i ++) printf("%d\n", t[pos[i]].sum);
}
int main()
{
init();
doit();
return 0;
}