https://codeforces.com/problemset/problem/291/E
题意:给你一颗树,然后每一条边有一个字符串,然后给你一个字符串,问这个字符在所有的树的根到叶子结点练成的串中,出现了多少次。
做法:建立AC自动机,每个点进行计数,在对询问串建AC自动机时不需要计数,然后dfs遍历fail树进行计数就可以了。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn = 300000 + 10;
const ll mod = 1000000000 + 7;
#define lowbit(x) x&-x
int nxt[maxn][26], fail[maxn], sum[maxn], tot;
int modify(string s, int now, int f) {
int len = s.size();
for (int i = 0; i < len; i++) {
int id = s[i] - 'a';
if (nxt[now][id] == 0) nxt[now][id] = ++tot;
now = nxt[now][id];
if (f) sum[now]++;
}
return now;
}
void build() {
queue<int> qu;
for (int i = 0; i < 26; i++) {
if (nxt[0][i] != 0) qu.push(nxt[0][i]);
}
while (!qu.empty()) {
int u = qu.front();
qu.pop();
for (int i = 0; i < 26; i++) {
if (nxt[u][i] != 0) fail[nxt[u][i]] = nxt[fail[u]][i], qu.push(nxt[u][i]);
else nxt[u][i] = nxt[fail[u]][i];
}
}
}
struct node {
int v, nxt;
string s;
} ed[maxn];
int head[maxn], cnt, now;
void add(int u, int v, string ss) {
++cnt;
ed[cnt].v = v;
ed[cnt].nxt = head[u];
ed[cnt].s = ss;
head[u] = cnt;
}
void dfs(int u, int cnt) {
for (int i = head[u]; i; i = ed[i].nxt) {
string tmp = ed[i].s;
int v = ed[i].v;
int tt = modify(tmp, cnt, 1);
dfs(v, tt);
}
}
vector<int> g[maxn];
void dfs_cnt(int u) {
for (auto x:g[u]) {
dfs_cnt(x);
sum[u] += sum[x];
}
}
int n, m, fa;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
now = 0;
string tt;
for (int i = 2; i <= n; i++) {
cin >> fa >> tt;
add(fa, i, tt);
}
dfs(1, now);
cin >> tt;
int ans = modify(tt, 0, 0);
build();
for (int i = 1; i <= tot; i++) g[fail[i]].push_back(i);
dfs_cnt(0);
cout << sum[ans] << endl;
return 0;
}
来源:CSDN
作者:KXL5180
链接:https://blog.csdn.net/KXL5180/article/details/103868493