|
|
#include <algorithm>
|
|
|
#include <iostream>
|
|
|
#include <cstring>
|
|
|
#include <cstdio>
|
|
|
#include <cmath>
|
|
|
#define QWQ cout << "QwQ" << endl;
|
|
|
#define ll long long
|
|
|
#include <vector>
|
|
|
#include <queue>
|
|
|
#include <stack>
|
|
|
#include <map>
|
|
|
#define ls now << 1
|
|
|
#define rs now << 1 | 1
|
|
|
using namespace std;
|
|
|
const int N = 401010;
|
|
|
const int qwq = 4003030;
|
|
|
const int inf = 0x3f3f3f3f;
|
|
|
int n, m;
|
|
|
int cnt;
|
|
|
char s[N];
|
|
|
struct T {
|
|
|
int to[28], faith, from;
|
|
|
} f[N]; // trie树
|
|
|
vector<int> d[N]; // fail指针树
|
|
|
vector<int> at[N]; // tire树上点是哪些串的结束。
|
|
|
vector<int> wen[N]; //这个点(即y串)有哪些问题。。.
|
|
|
vector<int> e[N]; //原来的树,因为我BFS时将原来的trie树改成了trie图,所以我需要记录最开始时的树。
|
|
|
queue<int> q;
|
|
|
int wei[N]; //此字符串结束位置。
|
|
|
int askman[N], ans[N]; //此问题:谁发起问题(即x串),问题答案;
|
|
|
int tree[qwq], id[N], siz[N];
|
|
|
|
|
|
void BFS() {
|
|
|
for (int i = 1; i <= 26; i++)
|
|
|
if (f[0].to[i]) q.push(f[0].to[i]);
|
|
|
while (!q.empty()) {
|
|
|
int u = q.front();
|
|
|
q.pop();
|
|
|
for (int i = 1; i <= 26; i++) {
|
|
|
int v = f[u].to[i];
|
|
|
if (v) {
|
|
|
f[v].faith = f[f[u].faith].to[i];
|
|
|
q.push(v);
|
|
|
} else
|
|
|
f[u].to[i] = f[f[u].faith].to[i];
|
|
|
}
|
|
|
}
|
|
|
for (int i = 1; i <= cnt; i++) d[f[i].faith].push_back(i); //建fail树。
|
|
|
}
|
|
|
|
|
|
void DFS1(int u) { //遍历fail树,算出每个点子树大小,并给每个点一个编号。
|
|
|
siz[u] = 1;
|
|
|
id[u] = ++cnt;
|
|
|
for (int i = 0; i < d[u].size(); i++) {
|
|
|
int v = d[u][i];
|
|
|
DFS1(v);
|
|
|
siz[u] += siz[v];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void insert(int now, int l, int r, int we, int g) { //单点修改
|
|
|
if (l == r) {
|
|
|
tree[now] += g;
|
|
|
return;
|
|
|
}
|
|
|
int mid = (l + r) >> 1;
|
|
|
if (we <= mid)
|
|
|
insert(ls, l, mid, we, g);
|
|
|
else
|
|
|
insert(rs, mid + 1, r, we, g);
|
|
|
tree[now] = tree[ls] + tree[rs];
|
|
|
}
|
|
|
|
|
|
int query(int now, int l, int r, int x, int y) { //区间查询
|
|
|
if (x <= l && r <= y) { return tree[now]; }
|
|
|
int mid = l + r >> 1, res = 0;
|
|
|
if (x <= mid) res += query(ls, l, mid, x, y);
|
|
|
if (y > mid) res += query(rs, mid + 1, r, x, y);
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
void TREE(int now) { //遍历原树
|
|
|
insert(1, 1, cnt, id[now], 1); //每到一个点就加上这个点的贡献
|
|
|
for (int i = 0; i < at[now].size(); i++) {
|
|
|
int u = at[now][i];
|
|
|
for (int j = 0; j < wen[u].size(); j++) {
|
|
|
int qu = wen[u][j], v = wei[askman[qu]]; // qu为问题编号,v为串x的结尾点
|
|
|
ans[qu] = query(1, 1, cnt, id[v], id[v] + siz[v] - 1);
|
|
|
}
|
|
|
}
|
|
|
for (int i = 0; i < e[now].size(); i++) TREE(e[now][i]);
|
|
|
insert(1, 1, cnt, id[now], -1);
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
int x, y;
|
|
|
scanf("%s", s);
|
|
|
int len = strlen(s), now = 0;
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
int v = s[i] - 'a' + 1;
|
|
|
if (s[i] == 'P') {
|
|
|
at[now].push_back(++n);
|
|
|
wei[n] = now;
|
|
|
continue;
|
|
|
}
|
|
|
if (s[i] == 'B') {
|
|
|
now = f[now].from;
|
|
|
continue;
|
|
|
}
|
|
|
if (!f[now].to[v]) f[now].to[v] = ++cnt, e[now].push_back(f[now].to[v]);
|
|
|
f[f[now].to[v]].from = now;
|
|
|
now = f[now].to[v]; //涉及到退格,需要记录from。
|
|
|
}
|
|
|
BFS();
|
|
|
cnt = 0;
|
|
|
DFS1(0);
|
|
|
scanf("%d", &m);
|
|
|
for (int i = 1; i <= m; i++) {
|
|
|
scanf("%d%d", &askman[i], &x);
|
|
|
wen[x].push_back(i);
|
|
|
}
|
|
|
TREE(0);
|
|
|
for (int i = 1; i <= m; i++)
|
|
|
printf("%d\n", ans[i]);
|
|
|
return 0;
|
|
|
} |