# BZOJ 2434 阿狸的打字机

http://www.lydsy.com/JudgeOnline/problem.php?id=2434

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
struct edge{
int to,next,id;
}que[500005];
int fail[500005],sz,ch[500005][26],root,num,hw,low[500005],dfn[500005];
char s[500005];
int pos[500005],id,fi[500005],first[500005],next[500005],tot,go[500005];
int fa[500005],ans[500005],V[1000005],n,m;
void insert(int x,int y){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
}
for (int i=x;i<=hw;i+=(i)&(-i)){
V[i]+=v;
}
}
int query(int x){
int res=0;
for (int i=x;i;i-=(i)&(-i)){
res+=V[i];
}
return res;
}
void build(){
int now=1;sz=1;
for (int i=0;i<n;i++){
if (s[i]=='P') pos[++id]=now;
else
if (s[i]=='B') now=fa[now];
else{
int k=s[i]-'a';
if (ch[now][k]==0) ch[now][k]=++sz,fa[sz]=now;
now=ch[now][k];
}
}
}
void bfs(){
std::queue<int>Q;
for (int i=0;i<26;i++)
if (!ch[root][i]) ch[root][i]=root;
else if (ch[root][i]){
fail[ch[root][i]]=root;
Q.push(ch[root][i]);
}
while (!Q.empty()){
int now=Q.front();Q.pop();
for (int i=0;i<26;i++)
if (!ch[now][i]){
ch[now][i]=ch[fail[now]][i];
}else{
fail[ch[now][i]]=ch[fail[now]][i];
Q.push(ch[now][i]);
}
}
}
void dfs(int x){
dfn[x]=++hw;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
dfs(pur);
}
low[x]=++hw;
}
void solve(){
int sx=0,now=1;
for (int i=0;i<n;i++){
if (s[i]=='P'){
sx++;
for (int j=fi[sx];j;j=que[j].next){
int pur=pos[que[j].to];
ans[que[j].id]+=query(low[pur])-query(dfn[pur]-1);
}//询问dfs序区间里面有多少标记过的节点，有多少就代表y到root路径上的节点有多少能走到x的尾节点
}else
else{
now=ch[now][s[i]-'a'];
}
}
}
int main(){
scanf("%s",s);root=1;
n=strlen(s);
build();
bfs();//建AC自动机
for (int i=1;i<=sz;i++)
insert(fail[i],i);//建fail树
dfs(0);//找dfs序
scanf("%d",&m);
for (int i=1;i<=m;i++){//把y相同的询问弄到一起
int x,y;
scanf("%d%d",&x,&y);
num++;
que[num].to=x;
que[num].next=fi[y];
que[num].id=i;
fi[y]=num;
}
solve();//统计答案
for (int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}

posted @ 2016-07-20 17:17  GFY  阅读(192)  评论(0编辑  收藏  举报