P3966 [TJOI2013]单词(AC自动机,fail树)
Posted H-w-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3966 [TJOI2013]单词(AC自动机,fail树)相关的知识,希望对你有一定的参考价值。
P3966 [TJOI2013]单词
题意:
给出n个字符串,问各个字符串在所有字符串中出现的次数
思路:
对于一个字符串来说,我们对它在trie树上的路径节点++,表示当前节点一共出现多少次。
再建一棵fail树,对于fail树的一个子树来说,子树权值等于根节点所表示的字符串出现的次数。
所以我们就可以dfs去统计每个子树的权值和,在输出每个字符串对应节点的权值,就是答案。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6+10;
int trie[N][30], val[N], tot;
int fail[N];
int head[N], nex[N], to[N], cnt = 0;
int xx[N];
void addE(int x, int y) {
nex[++cnt] = head[x];
to[cnt] = y;
head[x] = cnt;
}
int insert(char *x) {
int p = 0, len = strlen(x);
for(int i=0; i<len; i++) {
int u = x[i] - 'a';
if(!trie[p][u]) trie[p][u] = ++tot;
p = trie[p][u];
val[p]++;
}
return p;
}
int aa;
void bfs() {
queue<int> q;
for(int i=0; i<26; i++) {
if(trie[0][i]) q.push(trie[0][i]);
}
while(q.size()) {
int p = q.front(); q.pop();
xx[++aa] = p;
for(int i=0; i<26; i++) {
if(trie[p][i]) fail[trie[p][i]] = trie[fail[p]][i], q.push(trie[p][i]);
else trie[p][i] = trie[fail[p]][i];
}
}
for(int i=1; i<=tot; i++) {
// cout << fail[i] << ' ' << i << endl;
addE(fail[i], i);
}
}
void dfs(int x) {
for(int i=head[x]; i; i=nex[i]) {
// cout << x << ' ' << to[i] << endl;
dfs(to[i]);
val[x] += val[to[i]];
}
}
char s[N];
int idx[N];
signed main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n;
scanf("%lld", &n);
for(int i=1; i<=n; i++) {
scanf("%s", s);
idx[i] = insert(s);
}
bfs();
dfs(0);
// for(int i=aa; i>=1; i--) {
// val[fail[xx[i]]] += val[xx[i]];
// }
for(int i=1; i<=n; i++) {
printf("%lld\\n", val[idx[i]]);
}
return 0;
}
以上是关于P3966 [TJOI2013]单词(AC自动机,fail树)的主要内容,如果未能解决你的问题,请参考以下文章
P3966 [TJOI2013]单词(AC自动机,fail树)
bzoj3172: [Tjoi2013]单词 字符串-AC自动机