这道题要用到fail树,学习到了一点知识。
大概就是在一个字串尾节点上找另一段字串的全部节点指向此节点的fail有多少个。然后常规思路很明显没有办法,于是可以改成一颗fail树,从根节点出发通过fial路径连向每一个结点。查询的是子串,那么势必是长串fail指向子串尾节点,由此尾节点一定是长串中某些结点的fail树上的父亲结点。
一般这种在很短时间内统计个数深度的题目都会考虑到数据结构。联系到是树形,于是先搞出fail树的dfs序,然后in和out之间的编号是其所有子节点,维护一个树状数组,查询in和out这一段的sum即可。注意答案需要离线。由于此题的输入为连续模拟,于是acm建好后再模拟一遍,进入时树状数组+1,出队时-1,于是到某一'P'(尾节点)有标记的始终是当前的串上的节点,利用小串的尾节点in,out查询即可。
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
struct edge
{
int to,next;
}e[maxn],q[maxn];
int n,m;
int cnt_clock,icnt,qcnt;
char s[maxn];
int head[maxn],qhead[maxn];
int c[maxn<<1];
int in[maxn],out[maxn];
int ans[maxn];
void insert(int a,int b)
{
e[++icnt].to=b;e[icnt].next=head[a];head[a]=icnt;
}
void qinsert(int a,int b)
{
q[++qcnt].to=b;q[qcnt].next=qhead[a];qhead[a]=qcnt;
}
int query(int x)
{
int res=0;
for(int i=x;i>0;i-=i&(-i))res+=c[i];
return res;
}
void add(int x,int val)
{
for(int i=x;i<=cnt_clock;i+=i&(-i))c[i]+=val;
}
struct
{
int cnt,id;
int fail[maxn],next[maxn][27];
int pre[maxn],end[maxn];
void init()
{
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
qinsert(b,a);
}
cnt=1;
for(int i=0;i<26;i++)
next[0][i]=1;
}
void trie()
{
int now=1;
for(int i=1;i<=n;i++)
{
if(s[i]=='P')
end[++id]=now;
else if(s[i]=='B')now=pre[now];
else
{
if(!next[now][s[i]-'a'])next[now][s[i]-'a']=++cnt;
pre[next[now][s[i]-'a']]=now;
now=next[now][s[i]-'a'];
}
}
}
void getfail()
{
queue<int>q;
q.push(1);//这里老是写错
fail[1]=0;//
insert(0,1);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<26;i++)
if(next[u][i])
{
int now=fail[u];
while(now&&!next[now][i])now=fail[now];
fail[next[u][i]]=next[now][i];
insert(next[now][i],next[u][i]);
q.push(next[u][i]);
}
}
}
void solve()
{
int now=1;
id=0;
add(in[1],1);
for(int i=1;i<=n;i++)
{
if(s[i]=='P')
{
id++;
for(int i=qhead[id];i;i=q[i].next)
{
int x=end[q[i].to];
ans[i]=query(out[x])-query(in[x]-1);
}
}
else if(s[i]=='B')add(out[now],-1),now=pre[now];
else add(in[next[now][s[i]-'a']],1),now=next[now][s[i]-'a'];
}
}
void print()
{
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
}acm;
void dfs(int x)
{
in[x]=++cnt_clock;
for(int i=head[x];i;i=e[i].next)
dfs(e[i].to);
out[x]=++cnt_clock;
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
acm.init();
acm.trie();
acm.getfail();
dfs(0);
acm.solve();
acm.print();
return 0;
}