题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2434
大意:有3种操作,1、在末尾加入一个字符;2、删除末尾的一个字符;3、打印当前字符串。
m个询问,第a个打印出来的字符串在第b个打印出来的字符串中出现了几次。
首先建立AC自动机,第2个操作相当于跳到当前节点的父亲,第3个操作可以挂到节点上。
然后我们来研究询问。
可以发现,若a字符串出现在b字符串中,那通过b的fail肯定可以找到a。
这样我们可以将fail反向,建一棵fail树。一个字符串a出现的次数就是它在fail树中子树节点的值。
对于每个询问,我们照样把a挂到b上。
现在的问题是:支持节点修改,询问子树值。
那就直接Dfs序+树状数组就好啦。(都是好神的题,还是太弱了。。。)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct sef { int ne,en; }h[200050];
int tot,first[200050];
struct trie {
int son[27],fa,fail;
}T[200050];
int q[200050],ql;
int len,sum,Id[200050],num,pos[200050];
int To[200050],tim,siz[200050],ans[200050];
int d[200050];
int m;
char s[200050];
inline void setl(int x,int y)
{
h[++tot].ne=first[x]; h[tot].en=y;
first[x]=tot;
}
inline void Pre_Trie()
{
sum=1; int x=1,y;
for (int i=0;i<len;++i) {
if (s[i]=='P') { pos[++num]=x; Id[x]=num; }
else if (s[i]=='B') x=T[x].fa;
else {
y=s[i]-'a';
if (!T[x].son[y]) T[x].son[y]=++sum;
T[T[x].son[y]].fa=x;
x=T[x].son[y];
}
}
}
inline void Pre_Fail()
{
for (int i=0;i<26;++i) T[0].son[i]=1;
q[ql=1]=1;
int x,cur,y;
for (int i=1;i<=ql;++i) {
x=q[i];
for (int j=0;j<26;++j)
if (y=T[x].son[j]) {
cur=T[x].fail;
while (!T[cur].son[j]) cur=T[cur].fail;
cur=T[cur].son[j];
T[y].fail=cur;
setl(cur,y);
q[++ql]=y;
}
}
}
inline void Dfs(int x)
{
To[x]=++tim;
siz[x]=1;
for (int i=first[x];i;i=h[i].ne) {
Dfs(h[i].en);
siz[x]+=siz[h[i].en];
}
//Out[x]=++tim;
}
inline void Add(const int &x,int v)
{
for (int i=To[x];i<=sum;i+=i & (-i)) d[i]+=v;
//for (int i=To[x]+siz[x];i<=sum;i+=i & (-i)) d[i]-=v;
}
inline int Ask(int x)
{
int r=0;
for (int i=To[x]+siz[x]-1;i;i-=i & (-i)) r+=d[i];
for (int i=To[x]-1;i;i-=i & (-i)) r-=d[i];
return r;
}
inline void Query(int k)
{
int x=Id[k];
int y;
for (int i=first[x];y=h[i].en,i;i=h[i].ne)
ans[i]=Ask(pos[y]);
}
inline void Work()
{
int x=1,y;
for (int i=0;i<len;++i) {
if (s[i]=='P') Query(x);
else if (s[i]=='B') { Add(x,-1); x=T[x].fa; }
else {
y=s[i]-'a';
x=T[x].son[y]; Add(x,1);
}
}
}
int main()
{
scanf("%s",s);
len=strlen(s);
Pre_Trie();
Pre_Fail();
Dfs(1);
memset(first,0,sizeof(first));
tot=0;
scanf("%d",&m);
int x,y;
for (int i=1;i<=m;++i) {
scanf("%d%d",&x,&y);
setl(y,x);
}
Work();
for (int i=1;i<=m;++i) printf("%d\n",ans[i]);
}