前置知识:
ac自动机
fail树
关键在于fail树的应用:子节点的后缀一定包含父节点。
对于x在y中出现了多少次。
先假设y至少包含一个x。
那么在trie图中从根节点到y的那条链中一定存在某个节点的后缀是x。
所以找到这样的节点就能知道包含x的数量。
处理:
我们可以按照打字的顺序建图,记录一下tire图中的pre,当操作’B’的时候就跳到pre[u],对于’P’的操作记录一下时间戳,对应询问操作。否则就直接插入。
fail指针构建完后就可以构建fail树了,然后记录一下每个节点的子树范围。
然后我们就可以用刚才处理的信息来搞事情了。
别忘了 我们现在的问题是如何统计在y的链中并且后缀是x的节点。
记录答案:
可以把询问离线下来,一边处理字符串一边记录答案。
而我们想要的就是当前时间戳下fail树中x的子节点中有哪些节点是存在的。
可以用树状数组维护,插入字符时就把对应fail树的编号插入到树状数组里面,'B’操作我们就在树状数组中取消对应的编号,然后遇到时间戳,就看一下有没有当前时间戳的询问,树状数组查一下x的子节点区间里面的存在的个数。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
char ss[maxn];
struct AC{
int nex[maxn][26], tot, root;
int f[maxn], ed[maxn], pre[maxn], date[maxn];
vector<int>G[maxn];
int newnode() {
for(int i = 0; i < 26; i++)
nex[tot][i] = -1;
ed[tot] = 0;
return tot++;
}
void init() {
tot = 0;root = newnode();
}
void build() {
int len = strlen(ss), u = root, cnt = 0;
for(int i = 0; i < len; i++) {
if(ss[i] == 'P') date[++cnt] = u;
else if(ss[i] == 'B') u = pre[u];
else {
int ch = ss[i]-'a';
if(nex[u][ch] == -1) {
pre[nex[u][ch] = newnode()] = u;
}
u = nex[u][ch];
}
}
}
void getfail() {
queue<int>Q;
for(int i = 0; i < 26; i++) {
if(nex[root][i] == -1) nex[root][i] = root;
else {
f[nex[root][i]] = root;
Q.push(nex[root][i]);
}
}
while(!Q.empty()) {
int u = Q.front();Q.pop();
for(int i = 0; i < 26; i++) {
if(nex[u][i] == -1) nex[u][i] = nex[f[u]][i];
else {
f[nex[u][i]] = nex[f[u]][i];
Q.push(nex[u][i]);
}
}
}
for(int i = 1; i <= tot; i++) {
G[i].push_back(f[i]);
G[f[i]].push_back(i);
}
}
}ac;
int idx = 0, in[maxn], out[maxn], res[maxn];
void dfs(int u, int f) {
in[u] = ++idx;
for(int i = 0; i < ac.G[u].size(); i++) {
int v = ac.G[u][i];
if(v == f) continue;
dfs(v, u);
}
out[u] = idx;
}
class bit_tree{
private:
int tr[maxn], n;
public:
bit_tree(int n) {
this->n = n;
}
int lowerbit(int x) {
return ((x)&(-x));
}
void update(int pos, int val) {
while(pos <= n) {
tr[pos] += val;
pos += lowerbit(pos);
}
}
int query(int pos) {
int res = 0;
while(pos > 0) {
res += tr[pos];
pos -= lowerbit(pos);
}
return res;
}
};
struct node{
int x, id;
};
vector<node>ve[maxn];
void solve() {
int n;
scanf("%s", ss);
ac.init();
ac.build();
ac.getfail();
dfs(0, -1);
bit_tree t(idx);
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
int x, y;scanf("%d%d", &x, &y);
ve[y].push_back(node{x, i});
}
int u = ac.root, pos = 0, len = strlen(ss);
for(int i = 0; i < len; i++) {
if(ss[i] == 'B') {
t.update(in[u], -1);
u = ac.pre[u];
}
else if(ss[i] == 'P') {
pos++;int sz = ve[pos].size();
for(int j = 0; j < sz; j++) {
int v = ac.date[ve[pos][j].x], k = ve[pos][j].id;
res[k] = t.query(out[v])-t.query(in[v]-1);
}
}
else {
u = ac.nex[u][ss[i]-'a'];
t.update(in[u], 1);
}
}
for(int i = 1; i <= n; i++) {
printf("%d\n", res[i]);
}
}
int main() {
solve();
return 0;
}