转载请注明出处233:http://blog.csdn.net/vmurder/article/details/42875307
这是一道神题。
首先我们需要建立AC自动机,然后再建个Fail树,之后发现
如果询问a串在b串中出现了几次,那么只需要看b串在AC自动机上所有的节点中有多少个节点,在a串的结束节点在Fail树上的子树中就可以了。
然后这样做就很可以了,但是仍然不能AC,
这时我们只需要按照Fail树的dfs序建立数据结构(我写了树状数组)进行区间查询就好了。
这时对于以上的b串,我们按照dfs序扫一遍(按照输入时的字符串就是天然的优越dfs序),然后每转移一个节点,就在数据结构上加加减减、、
然后对于每个‘B’,挂链询问中问了哪些‘A’在其中出现了多少次,树状数组O(logn)查一次就好了。
单点修改区间查询,时间复杂度mlogn。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define MAX 220000
#define T 26
using namespace std;
struct FAIL
{
int v[N],next[N],head[N],cnt;
void cls()
{
cnt=0;
memset(head,0,sizeof head);
}
void add(int u,int _v)
{
v[++cnt]=_v;
next[cnt]=head[u];
head[u]=cnt;
}
int in[N],out[N],dfn;
void build_dfn(int x=0)
{
in[x]=++dfn;
for(int i=head[x];i;i=next[i])
build_dfn(v[i]);
out[x]=++dfn;
}
}Fail;
struct FENWICK //树状数组
{
int fenwick[MAX];
inline void add (int x,int w)
{
for(x=Fail.in[x];x<MAX;x+=(x&-x))
fenwick[x]+=w;
}
inline int query(int x)
{
int ans=0,temp=x;
for(x=Fail.out[temp] ;x;x-=(x&-x))ans+=fenwick[x];
for(x=Fail.in[temp]-1;x;x-=(x&-x))ans-=fenwick[x];
return ans;
}
}fw;
struct TRIE
{
int pa[N],next[N][T],fail[N];
int end[N],crs[N];
int root,cnt,id;
char s[N];
void build_trie() // 建立Trie
{
scanf("%s",s);
int i,x=root=0,alp;
for(i=0;s[i];i++)
{
if(s[i]=='P')end[x]=++id,crs[id]=x;
else if(s[i]=='B')x=pa[x];
else {
alp=s[i]-'a';
if(!next[x][alp])next[x][alp]=++cnt,pa[cnt]=x;
x=next[x][alp];
}
}
}
void build_fail() // 建立AC自动机
{
queue<int>q;
q.push(root);
int i,u,v,temp;
while(!q.empty())
{
u=q.front(),q.pop();
for(i=0;i<T;i++)if(v=next[u][i])
{
if(u==root)fail[v]=root;
else {
temp=fail[u];
while(temp&&!next[temp][i])temp=fail[temp];
fail[v]=next[temp][i];
}
q.push(v);
Fail.add(fail[v],v);
}
}
}
int v[N],nxt[N],head[N];
void add(int u,int _v) // 询问离线
{
v[++cnt]=_v;
nxt[cnt]=head[u];
head[u]=cnt;
}
int m,fians[N];
void input() // 输入询问
{
int a,b;
scanf("%d",&m);
cnt=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
add(b,a);
}
}
void query(int pdd)
{
for(int i=head[pdd];i;i=nxt[i])
fians[i]=fw.query(crs[v[i]]);
}
void work() // 遍历B串
{
int i,x=root=0,alp,now;
for(i=0;s[i];i++)
{
if(s[i]=='P')query(end[x]);
else if(s[i]=='B')fw.add(x,-1),x=pa[x];
else {
alp=s[i]-'a';
x=next[x][alp];
fw.add(x,1);
}
}
return ;
}
void output() // 输出答案
{for(int i=1;i<=m;i++)printf("%d\n",fians[i]);}
}Trie;
int main()
{
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
Trie.build_trie();
Trie.build_fail();
Fail.build_dfn();
Trie.input();
Trie.work();
Trie.output();
return 0;
}