先把所有输出的字符串建成 Trie
T
r
i
e
树,但不用存字符串,因为输入字符的过程就相当于在 Trie
T
r
i
e
树上走。
考虑暴力的做法:
建出 fail
f
a
i
l
指针。
对于每次查询,沿着第 y
y
个字符串在 Trie 树上的节点跳 fail
f
a
i
l
,统计跳到的点是第 x
x
个字符串结束位置的个数。
对于相同 y 的询问离线一同处理。
反过来想,对于 Trie
T
r
i
e
树上节点 i
i
将 fail[i] 向 i
i
连一条边,建成一棵树,则问题的实质就被转化为求第 x 个字符串结束位置所在的点的子树中有多少个点属于第 y
y
个字符串。
因此在 Trie 树上 DFS
D
F
S
,每到一个点打上 +1
+
1
标记,退回上一步时打上 −1
−
1
标记,则每到达第 y
y
个字符串的结束位置时,求相关 y 的询问中第 x 个字符串结束位置所在的点的子树和,就是问题的答案了。
直接在树上动态求子树和并不好做(树剖??),所以我们利用 DFS
D
F
S
序,把子树和转化为求序列上的一段区间和,可以用树状数组维护。
时间复杂度 O(nlogn)
O
(
n
log
n
)
。
Code
#include <cstdio>#include <iostream>#include <cctype>#include <cstring>#include <cstdlib>#include <algorithm>usingnamespacestd;
constint N = 1e5 + 5;
int G[N][26], pos[N], idx[N], fa[N], h[N];
int dfn[N], low[N], fail[N], c[N], ans[N]; char s[N];
int n, m, tis, T = 1;
inlineint get()
{
char ch; int res = 0; bool flag = false;
while (ch = getchar(), !isdigit(ch) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (ch = getchar(), isdigit(ch))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
struct Question
{
int x, y, t, s;
inlinebooloperator < (const Question &a) const
{
return y < a.y;
}
}q[N], g[N];
struct Edge
{
int to; Edge *nxt;
}p[N], *lst[N], *P = p;
inlinevoid Link(int x, int y)
{
(++P)->nxt = lst[x]; lst[x] = P; P->to = y;
}
inlinevoid Bfs()
{
for (int i = 0; i < 26; ++i) G[0][i] = 1;
h[1] = 1; int t = 0, w = 1, x, y;
while (t < w)
{
x = h[++t];
for (int i = 0; i < 26; ++i)
if (G[x][i])
{
h[++w] = G[x][i];
y = fail[x];
while (y > 0 && !G[y][i]) y = fail[y];
fail[G[x][i]] = G[y][i];
}
}
}
inlinevoid Dfs1(int x)
{
dfn[x] = ++tis;
for (Edge *e = lst[x]; e; e = e->nxt)
Dfs1(e->to);
low[x] = tis;
}
inlinevoid Modify(int x, int y)
{
for (; x <= tis; x += x & -x)
c[x] += y;
}
inlineint Query(int x)
{
int res = 0;
for (; x; x -= x & -x)
res += c[x];
return res;
}
inlinevoid Dfs2(int x)
{
Modify(dfn[x], 1);
if (idx[x])
for (int i = g[idx[x]].x, im = g[idx[x]].y; i <= im; ++i)
q[i].s = Query(low[pos[q[i].x]]) - Query(dfn[pos[q[i].x]] - 1);
for (int i = 0; i < 26; ++i)
if (G[x][i]) Dfs2(G[x][i]);
Modify(dfn[x], -1);
}
int main()
{
scanf("%s", s + 1); int x = 1;
for (int i = 1, im = strlen(s + 1); i <= im; ++i)
if (s[i] == 'B')
x = fa[x];
elseif (s[i] == 'P')
pos[++n] = x, idx[x] = n;
else
{
int y = s[i] - 'a';
if (!G[x][y]) fa[G[x][y] = ++T] = x;
x = G[x][y];
}
Bfs();
for (int i = 1; i <= T; ++i) Link(fail[i], i);
Dfs1(0);
m = get();
for (int i = 1; i <= m; ++i)
q[i].x = get(), q[i].y = get(), q[i].t = i;
sort(q + 1, q + m + 1);
int l = 1, r;
while (l < m)
{
r = l;
while (r < m && q[l].y == q[r + 1].y) ++r;
g[q[l].y].x = l; g[q[l].y].y = r;
l = r + 1;
}
Dfs2(1);
for (int i = 1; i <= m; ++i)
ans[q[i].t] = q[i].s;
for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return0;
}