传送门1
传送门2
写在前面:15行的树状数组和35行的AC自动机和40行主程,你会先检查哪个?
思路:纠结了好久的自动机题目,不论网上的神犇们怎么说,蒟蒻就是觉得好难啊(/ □ ),算是学了一门新姿势了吧——fail树+dfs序树状数组维护AC自动机上的信息,纠结了许久,磨出来以后又和黄学长std拍了好久,发现操作几乎改的一模一样但答案还是不对,自动机和dfs改了又改,差点就推翻重写了,最后发现自己的get函数没有返回值……加上return以后又改回原程序,终于过了样例(但是T了5组?_?),之后像在hdu上做题一样把字符串长度赋给一个变量,就A了= =
网上貌似有很多详细(xuan xue)的讲解,蒟蒻还说么……推荐黄学长和Timemachine
(感觉自动机还是理解不够深刻,但时间好紧迫还有好多事没做啊啊啊)
注意:建fail树是单向边,父亲->儿子
代码:
#include<bits/stdc++.h>
#define low(x) (x&(-x))
using namespace std;
int m,x,y,root=1,tot=1,cnt,id,sum;//cnt记录自动机上的编号,id是建fail树时的边数
int d[200010],ans[100010],fail[100010],fa[100010],num[100010],trie[100010][26],first[100010],L[100010],R[100010];//L,R分别代表节点的进入,出去的顺序号
char s[200010];
queue<int>team;
struct edge
{
int u,v,next;
}e[100010];
struct node
{
int x,y,ind;
bool operator <(const node other)const
{
return y<other.y;
}
}q[100010];
void add(int x,int y)
{
e[++id].u=x;
e[id].v=y;
e[id].next=first[x];
first[x]=id;
}
int get(int x)
{
int sum=0;
while (x){
sum+=d[x];
x-=low(x);
}
return sum;
}
void update(int x,int y)
{
while (x<=sum){
d[x]+=y;
x+=low(x);
}
}
void insert(char s[])
{
int len=strlen(s),now=root,pos=0;
for (int i=0;i<len;i++)
{
if (s[i]=='B') now=fa[now];
else if (s[i]=='P') num[++cnt]=now;
else
{
if (!trie[now][s[i]-'a'])
trie[now][s[i]-'a']=++tot,
fa[tot]=now;
now=trie[now][s[i]-'a'];
}
}
}
void build()
{
int now,tmp;
team.push(root);
while (!team.empty())
{
now=team.front();
team.pop();
for (int i=0;i<26;i++)
if (trie[now][i])
{
tmp=fail[now];
while (tmp&&!trie[tmp][i]) tmp=fail[tmp];
if (tmp&&now!=root) fail[trie[now][i]]=trie[tmp][i];
else fail[trie[now][i]]=root;
team.push(trie[now][i]);
}
}
}
void dfs(int x)
{
L[x]=++sum;
for (int i=first[x];i;i=e[i].next)
dfs(e[i].v);
R[x]=sum;
}
main()
{
scanf("%s",s);
insert(s);
build();
for (int i=1;i<=tot;i++) add(fail[i],i);
dfs(root);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].x,&q[i].y);
q[i].ind=i;
}
sort(q+1,q+m+1);
int k=0,now=root,t=1,len=strlen(s);
for (int i=0;i<len;i++)
{
if (s[i]=='P')
{
k++;
if (k==q[t].y)
{
while (q[t].y==k)
{
ans[q[t].ind]=get(R[num[q[t].x]])-get(L[num[q[t].x]]-1);
t++;
if (t>m) break;
}
}
}
else if (s[i]=='B') update(L[now],-1),now=fa[now];
else now=trie[now][s[i]-'a'],update(L[now],1);
}
for (int i=1;i<=m;i++)printf("%d\n",ans[i]);
}