一道AC自动机好题啊,做完了以后对AC自动机有了一个新的认识,首先由于这道题的特殊性我们无需一个一个字符串插入,只要维护一个father指针往回跳就行了,建好树了以后怎么办呢,我们可以想到A在AC自动机上是B的子串当且仅当B的节点跳fail指针可以跳到A,但是这样时间复杂度太大,由于fail指针总是由下向上指所以我们能想得到如果将fail倒过来那么将形成一颗树,我们称之为fail树,那么B的节点跳fail能跳到A等价于B的节点在A的子树中,我们只需维护A的子树中有多少B的节点就好了,我们只要维护一下dfs序就可快速得知子树信息,用树状数组就可以区间求和,由于这道题的特殊性,将询问按照y值排序,我们只需再跑一边字符串就可nlogn维护树状数组,这样这道题就解决了
1A ^_^
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
struct Trie
{
Trie *son[26],*fail,*fa;
int num;
int wz;
Trie()
{
memset(son,0,sizeof(son));
fa=fail=NULL;
num=0;
}
}mempool[1000000],*root=&mempool[0];
int toppp=0;
int top=0;
void my_insert(char *s)
{
root->fa=root;
Trie *o=root;
while(*s)
{
if(*s=='B') o=o->fa;
else if(*s=='P') o->num=++top;
else
{
if(!o->son[*s-'a'])
{
o->son[*s-'a']=&mempool[++toppp];
o->son[*s-'a']->fa=o;
}
o=o->son[*s-'a'];
}
s++;
}
}
struct edge
{
int l,r;
}a[1000000];
int fir[1000000];
int nex[1000000];
int tot=0;
void add_edge(int l,int r)
{
a[++tot].l=l;
a[tot].r=r;
nex[tot]=fir[l];
fir[l]=tot;
}
void bfs()
{
static Trie* dui[1000000];
int top=1,my_final=1;
for(int i=0;i<26;i++)
{
if(root->son[i])
{
root->son[i]->fail=root;
add_edge(root->wz,root->son[i]->wz);
dui[my_final++]=root->son[i];
}
else root->son[i]=root;
}
while(top<my_final)
{
Trie *o=dui[top++];
for(int i=0;i<26;i++)
{
if(o->son[i])
{
dui[my_final++]=o->son[i];
o->son[i]->fail=o->fail->son[i];
add_edge(o->fail->son[i]->wz,o->son[i]->wz);
}
else o->son[i]=o->fail->son[i];
}
}
}
int dfsx[1000000];
int wz[1000000];
int tott=0;
int my_begin[1000000];
int my_end[1000000];
int c[1000000];
int mapp[1000000];
void dfs(int u,int from)
{
dfsx[++tott]=u;
my_begin[u]=tott;
if(mempool[u].num) mapp[mempool[u].num]=u;
for(int o=fir[u];o!=0;o=nex[o])
if(a[o].r!=from) dfs(a[o].r,u);
dfsx[++tott]=u;
my_end[u]=tott;
}
struct query
{
int x,y,num;
bool operator <(query b) const
{
return y<b.y;
}
}queries[1000000];
int ans[1000000];
inline void add_v(int x,int v)
{
for(int i=x;i<=tott;i+=i&-i) c[i]+=v;
}
inline int my_search(int l,int r)
{
int re=0;
for(int i=r;i;i-=i&-i) re+=c[i];
for(int i=l-1;i;i-=i&-i) re-=c[i];
return re;
}
int pipei=1;
void search_ans(char *s)
{
Trie *o=root;
add_v(my_begin[root->wz],1);
while(*s)
{
if(*s=='B')
{
add_v(my_begin[o->wz],-1);
o=o->fa;
}
else if(*s=='P')
{
while(queries[pipei].y==o->num)
{
ans[queries[pipei].num]=my_search(my_begin[mapp[queries[pipei].x]],my_end[mapp[queries[pipei].x]]);
pipei++;
}
}
else
{
o=o->son[*s-'a'];
add_v(my_begin[o->wz],1);
}
s++;
}
}
char s[1000000];
int main()
{
scanf("%s",s);
my_insert(s);
for(int i=0;i<=toppp;i++) mempool[i].wz=i;
bfs();
dfs(0,-1);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d%d",&queries[i].x,&queries[i].y),queries[i].num=i;
sort(queries+1,queries+1+m);
search_ans(s);
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
}