https://www.luogu.org/problem/P2414
分析
容易发现询问串A属于串B多少次就是问访问串B时,跳完每个点的fail链,到达串A末尾的次数
可以发现如果把fail树建出来,就相当于每到达一个点,就往fail树里面权值+1,离开时-1,当到达串B末尾时,询问串A末尾在fail树中子树的权值和
用DFS序和树状数组可以轻松解决

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define lowbit(x) x&-x
using namespace std;
const int N=2e5+10;
struct Graph {
int v,nx;
}g[N];
int gcnt,list[N];
int fail[N],t[N][26],cnt,v[N];
struct Query {
int x,y,id;
}q[N];
int m,len,tme,p;
int l[N],r[N],end[N],ans[N],f[N];
char c[N];
void Add(int u,int v) {
g[++gcnt]=(Graph){v,list[u]};list[u]=gcnt;
}
bool CMP(Query a,Query b) {
return a.y<b.y;
}
void Insert() {
int x=0,id=0;
for (int i=1,n=strlen(c+1);i<=n;i++) {
if (c[i]=='B') {
x=f[x];
continue;
}
if (c[i]=='P') {
end[++id]=x;
continue;
}
if (!t[x][c[i]-'a']) f[t[x][c[i]-'a']=++cnt]=x;
x=t[x][c[i]-'a'];
}
}
void Build() {
queue<int> q;
while (!q.empty()) q.pop();
for (int i=0;i<26;i++) if (t[0][i]) q.push(t[0][i]),Add(0,t[0][i]);
while (!q.empty()) {
int u=q.front();q.pop();
for (int i=0;i<26;i++)
if (t[u][i]) {
int now=fail[u];
while (now&&!t[now][i]) now=fail[now];
fail[t[u][i]]=t[now][i];Add(t[now][i],t[u][i]);
q.push(t[u][i]);
}
}
}
void DFS(int u) {
l[u]=++tme;
for (int i=list[u];i;i=g[i].nx) DFS(g[i].v);
r[u]=tme;
}
void Addc(int x,int c) {
for (;x<=tme;x+=lowbit(x)) v[x]+=c;
}
int Sum(int x) {
int ans=0;
for (;x;x-=lowbit(x))ans+=v[x];
return ans;
}
void Trie() {
int x=0;
for (int i=1,n=strlen(c+1);i<=n;i++) {
if (c[i]=='B') {
Addc(l[x],-1);x=f[x];
continue;
}
if (c[i]=='P') {
while (end[q[p].y]==x) ans[q[p].id]=Sum(r[end[q[p].x]])-Sum(l[end[q[p].x]]-1),p++;
continue;
}
x=t[x][c[i]-'a'];Addc(l[x],1);
}
}
int main() {
scanf("%s",c+1);
Insert();
scanf("%d",&m);
for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].id=i;
sort(q+1,q+m+1,CMP);
Build();
DFS(0);
p=1;len=0;Trie();
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
