题意:
按输入串\(s\)建\(AC\)自动机即可。
\('B'\)相当于在\(trie\)树上从\(u\)点回退到\(u\)的父亲,遇到\('P'\)用\(vis\)数组记录一下当前串在\(trie\)的位置。
分析:
此题可考虑离线询问,每遍历题目所给的字符串的一个\(P\),就计算这个\(P\)代表第\(y\)个串的贡献,比如遍历到第二个\(P\),则解决所有\((x,2)\)的询问,如果有的话。
如何计算第\(x\)个串在第\(y\)个串出现的次数:
先将自动机的\(fail\)树建好,然后在\(trie\)上向下走\(s\)串,每走过一个节点,就让这个节点在\(fail\)树上的节点到\(fail\)树上的根这条路径出现的串的次数通通加\(1\)。
不难发现在\(fail\)树上,\(u\)节点到根节点的所有串都是\(u\)的后缀,反过来也就是说\(u\)节点的祖先都是\(u\)的子串。那么如果在\(trie\)树上走到\(u\)点有询问要处理,我们查询\(x\)串在\(fail\)树上对应的节点的子树的串的出现次数就好了(\(x\)串肯定是其子树的任意一个串的子串)。查询子树和\(dfs\)序用树状数组维护即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int N = 100000 + 5;
int q, x, y;
int tot, num, len, vis[N], ch[N][26], pre[N], fail[N];
int cur, dfn[N], edfn[N];
int bit[N], ans[N];
char s[N];
vector<int> g[N];
vector<pair<int, int> > v[N];
void init() {
len = strlen(s);
int u = 0, p, f;
for (int i = 0; i < len; i++) {
if (s[i] == 'B') {
u = pre[u];
} else if (s[i] == 'P') {
vis[++num] = u;
} else {
p = s[i] - 'a';
if (!ch[u][p]) ch[u][p] = ++tot;
f = u;
u = ch[u][p];
pre[u] = f;
}
}
}
void getfail() {
queue<int> q;
for (int i = 0; i < 26; i++) if (ch[0][i]) q.push(ch[0][i]);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; i++) {
if (ch[u][i]) {
fail[ch[u][i]] = ch[fail[u]][i];
q.push(ch[u][i]);
} else {
ch[u][i] = ch[fail[u]][i];
}
}
}
}
void dfs(int u) {
dfn[u] = ++cur;
for (auto v : g[u]) {
dfs(v);
}
edfn[u] = cur;
}
void update(int x, int w) {
for (int i = x; i <= cur; i += (i & -i)) bit[i] += w;
}
int query(int x) {
int res = 0;
for (int i = x; i; i -= (i & -i)) res += bit[i];
return res;
}
void solve() {
int u = 0, k = 0;
for (int i = 0; i < len; i++) {
if (s[i] == 'B') {
update(dfn[u], -1);
u = pre[u];
} else if (s[i] == 'P'){
++k;
for (auto it : v[k]) {
ans[it.se] = query(edfn[vis[it.fi]]) - query(dfn[vis[it.fi]] - 1);
}
} else {
u = ch[u][s[i] - 'a'];
update(dfn[u], 1);
}
}
}
int main() {
scanf("%s", s);
init();
getfail();
for (int i = 1; i <= tot; i++) g[fail[i]].pb(i);
dfs(0);
scanf("%d", &q);
for (int i = 1; i <= q; i++) {
scanf("%d %d", &x, &y);
v[y].pb(mp(x, i));
}
solve();
for (int i = 1; i <= q; i++) {
printf("%d\n", ans[i]);
}
return 0;
}