题目链接
- AC自动机的fail指针构成了失配树
- 把询问全部放到树上,离线dfs处理(第一遍dfs在fail树上进行,刻画x的出现;第二遍dfs在trie树上进行,利用系统栈刻画y的每个状态)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
string s;
int t[100005][26],tot,cnt,r[100005],fa[100005],fail[100005],dfn[100005],w[100005],sum,ans[100005];
bool b[100005];
vector<int>a[100005];
vector<int>o[100005];
vector<int>g[100005];
queue<int>q;
struct u1
{
int id,x,y;
}u[100005];
void build()
{
int cur=0;
for(int i=0;i<s.size();i++)
{
if(s[i]=='B')
{
cur=fa[cur];
}
else if(s[i]=='P')
{
cnt++;
r[cnt]=cur;
b[cur]=true;
}
else
{
if(t[cur][s[i]-'a']==0)
{
tot++;
t[cur][s[i]-'a']=tot;
fa[tot]=cur;
o[cur].push_back(tot);
}
cur=t[cur][s[i]-'a'];
}
}
for(int i=0;i<26;i++)
{
if(t[0][i]!=0)
{
q.push(t[0][i]);
}
}
while(!q.empty())
{
int n1=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(t[n1][i]!=0)
{
fail[t[n1][i]]=t[fail[n1]][i];
q.push(t[n1][i]);
}
else
{
t[n1][i]=t[fail[n1]][i];
}
}
}
for(int i=1;i<=tot;i++)
{
a[fail[i]].push_back(i);
}
}
void dfs1(int n1)
{
sum++;
dfn[n1]=sum;
w[n1]=1;
for(int i=0;i<a[n1].size();i++)
{
dfs1(a[n1][i]);
w[n1]+=w[a[n1][i]];
}
}
int c[100005];
int lowbit(int n)
{
return n&(-n);
}
void add(int n1,int va)
{
while(n1<=sum)
{
c[n1]+=va;
n1+=lowbit(n1);
}
}
int ask(int n1)
{
int s=0;
while(n1>0)
{
s+=c[n1];
n1-=lowbit(n1);
}
return s;
}
void dfs2(int n1)
{
add(dfn[n1],1);
for(int i=0;i<g[n1].size();i++)
{
int x=u[g[n1][i]].x;
ans[g[n1][i]]=ask(dfn[x]+w[x]-1)-ask(dfn[x]-1);
}
for(int i=0;i<o[n1].size();i++)
{
dfs2(o[n1][i]);
}
add(dfn[n1],-1);
}
int main()
{
cin>>s;
build();
dfs1(0);
int m;
cin>>m;
for(int i=1;i<=m;i++)
{
u[i].id=i;
u[i].x=r[read1()];
u[i].y=r[read1()];
g[u[i].y].push_back(u[i].id);
}
dfs2(0);
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}