[Codeforces 1207G] Indie Album
https://codeforces.ml/contest/1207/problem/G
题意:
给你一棵字典树,每次询问给定一个模式串和字典树上的一个前缀串,问模式串在这个前缀串中出现了多少次。
思路:
如果文本串是单串的话,就是 \(AC\) 自动机板子题了。现在把文本串放到了 \(Trie\) 上,但由于都是前缀串,很容易想到将询问离线,用 \(dfs\) 的方式去遍历 \(Trie\) ,然后出来再消去影响就行了。但是自动机上的其他模式串会对当前答案造成影响。我们考虑 \(fail\) 指针的作用,指向最长后缀所在的节点,所以如果在 \(AC\) 自动机上到达了某一模式串,一直反方向跑 \(fail\) 指针,都是合法的,反之都不合法。那么我们根据 \(fail\) 树跑一遍欧拉序,用数据结构维护子树的权值和,就能解决了。
文本串也不用真的建 \(Trie\) ,直接塞到 \(vector\) 里就行,可以减少码量和空间复杂度,好写很多。
好久没写 \(AC\) 自动机了,都快忘光了,赶紧写道复习下,欸嘿。
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
int f = 0; int x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
if (f) x = -x;
return x;
}
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 4e5 + 7;
struct Bit {
vector<int> bit;
int n;
void init(int N) {
n = N;
bit.resize(n + 1, 0);
}
int lowbit(int x) {
return x & -x;
}
int add(int i, int x) {
while (i <= n) {
bit[i] += x;
i += lowbit(i);
}
}
int query(int i) {
int res = 0;
while (i) {
res += bit[i];
i -= lowbit(i);
}
return res;
}
}b;
vector< pair<int, int> > qvec[N], svec[N];
int ans[N];
struct ACAM{
struct node{
int nx[26];
int fail;
void init() {
memset(nx, -1, sizeof(nx));
fail = 0;
}
}t[N];
int root, tot, cnt;
int stt[N], fnt[N];
vector<int> G[N];
int newnode() {
t[++tot].init();
return tot;
}
void init() {
tot = 0;
root = newnode();
}
int insert(char *s) {
int len = strlen(s);
int now = root;
for (int i = 0; i < len; ++i) {
if (t[now].nx[s[i] - 'a'] == -1) t[now].nx[s[i] - 'a'] = newnode();
now = t[now].nx[s[i] - 'a'];
}
return now;
}
void getFail() {
for (int i = 0; i < 26; ++i) t[0].nx[i] = 1;
queue<int> q;
q.push(1);
t[1].fail = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0 ; i < 26; ++i) {
int v = t[u].nx[i];
int Fail = t[u].fail;
if (v == -1) {
t[u].nx[i] = t[Fail].nx[i];
continue;
}
t[v].fail = t[Fail].nx[i];
q.push(v);
}
}
}
void getDfn(int u) {
stt[u] = ++cnt;
for (auto v : G[u]) {
getDfn(v);
}
fnt[u] = cnt;
}
void dfs(int u, int o) {
b.add(stt[o], 1);
for (auto [v, id] : qvec[u]) {
ans[id] = b.query(fnt[v]) - b.query(stt[v] - 1);
}
for (auto [ch, v] : svec[u]) {
int oo = t[o].nx[ch];
dfs(v, oo);
}
b.add(stt[o], -1);
}
void solve() {
getFail();
cnt = 0;
for (int i = 1; i <= tot; ++i) {
G[t[i].fail].push_back(i);
}
getDfn(1);
b.init(tot);
dfs(0, 1);
}
}acam;
int n, ord[N];
char s[N];
int main(){
acam.init();
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
int op = rd();
if (op == 1) {
scanf("%s", s);
svec[0].emplace_back(s[0] - 'a', i);
} else {
int id = rd();
scanf("%s", s);
svec[id].emplace_back(s[0] - 'a', i);
}
}
int q = rd();
for (int i = 1; i <= q; ++i) {
int id = rd();
scanf("%s", s);
qvec[id].emplace_back(acam.insert(s), i);
}
acam.solve();
for (int i = 1; i <= q; ++i) {
printf("%d\n", ans[i]);
}
return 0;
}