Description |
Given nnn strings, mmm asks how many times the xxx string appears in the yyy string. n,m≤105n,m\le10^5n,m≤105
Solution |
Establishing AC automata and failfailfail tree, the problem is transformed into: how many nodes in the subtree of termination node of xxx string in failfailfailfail tree belong to yyy string.
Find out the dfsdfsdfs order of the failfailfail tree, ask offline, and mark the end node of yyy.
On the AC automaton, for every point reached, the order of the dfsdfsdfs is + 1 + 1 + 1 in the tree array, and then − 1-1 − 1 when leaving. In this way, the chain from the current point to point 000 is stored in the tree array. If the current point is marked, the sum of the subtrees of xxx can be queried on the tree array.

#include <queue> #include <cstdio> #include <cstring> const int N = 100002; struct List { struct Edge { int v, nxt; } e[N]; int head[N], tot; void adde(int u, int v) { e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v; } } a, b; int siz[N], dfn[N], cnt, ch[N][26], tr[N][26]; int fa[N], fail[N], ed[N], ans[N], sum[N], sz; char s[N]; int read() { int x = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); return x; } void update(int x, int y) { while (x <= sz + 1) sum[x] += y, x += x & (-x); } int query(int x) { int res = 0; while (x) res += sum[x], x -= x & (-x); return res; } void build() { int n = strlen(s), x = 0; for (int i = 0; i < n; ++i) { if (s[i] == 'P') ed[++ed[0]] = x; else if (s[i] == 'B') x = fa[x]; else { int c = s[i] - 'a'; if (!ch[x][c]) tr[x][c] = ch[x][c] = ++sz, fa[ch[x][c]] = x; x = ch[x][c]; } } for (int i = 0; i <= sz; ++i) a.head[i] = b.head[i] = -1; std::queue<int> q; for (int i = 0; i < 26; ++i) if (ch[0][i]) a.adde(0, ch[0][i]), q.push(ch[0][i]); while (!q.empty()) { int x = q.front(); q.pop(); for (int i = 0; i < 26; ++i) { if (!ch[x][i]) ch[x][i] = ch[fail[x]][i]; else { fail[ch[x][i]] = ch[fail[x]][i]; a.adde(fail[ch[x][i]], ch[x][i]), q.push(ch[x][i]); } } } } void dfs1(int u) { siz[u] = 1, dfn[u] = ++cnt; for (int i = a.head[u]; ~i; i = a.e[i].nxt) dfs1(a.e[i].v), siz[u] += siz[a.e[i].v]; } void dfs2(int u) { update(dfn[u], 1); for (int i = b.head[u]; ~i; i = b.e[i].nxt) ans[i] = query(dfn[b.e[i].v] + siz[b.e[i].v] - 1) - query(dfn[b.e[i].v] - 1); for (int i = 0; i < 26; ++i) if (tr[u][i]) dfs2(tr[u][i]); update(dfn[u], -1); } int main() { scanf("%s", s), build(), dfs1(0); int m = read(); for (int i = 1, x, y; i <= m; ++i) x = read(), y = read(), b.adde(ed[y], ed[x]); dfs2(0); for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]); return 0; }