传送门
解题思路
被细节卡了一上午wwww
很好地一道题,考察了AC自动机的本质。
先考虑如何暴力做:枚举y中的每一位,并不断跳fail,若跳到了x,则ans++。
如何优化这个过程呢?
先离线根据y从小到大排序。
当我们以0为根节点,fail[now]向now连边时,AC自动机就变成了一颗树。这时我们把上述问题放在树上,就变成了询问以x的结尾为根的子树里有多少位y。
可以用dfs序+树状数组/线段树实现。
具体建AC自动机过程:
- B:now-->fa[now]
- P:打标记
- 字符:继续走。
求解过程:
- B: dfn[now]对应的点权-1,now-->fa[now]
- P:回答询问,查询区间和。
- 字符:继续走,并使dfn[now]对应的点权+1
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxn=1e5+5;
int n,m,cnt,p[maxn],siz[maxn],dfn[maxn],times,fa[maxn],num[maxn],tr[maxn][30],fail[maxn],tot,d[maxn];
string s;
struct node{
int v,next;
}e[maxn];
struct Node{
int x,y,id,ans;
}q[maxn];
bool cmp1(Node a,Node b){
return a.y<b.y;
}
bool cmp2(Node a,Node b){
return a.id<b.id;
}
void insert(int u,int v){
cnt++;
e[cnt].v=v;
e[cnt].next=p[u];
p[u]=cnt;
}
void dfs(int u){
siz[u]=1;
dfn[u]=++times;
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
dfs(v);
siz[u]+=siz[v];
}
}
void inserts(){
int len=s.length(),now=0;
for(int i=0;i<len;i++){
if(s[i]=='B') now=fa[now];
else if(s[i]=='P') num[++m]=now;
else{
if(tr[now][s[i]-'a']) now=tr[now][s[i]-'a'];
else{
tr[now][s[i]-'a']=++tot;
fa[tot]=now;
now=tot;
}
}
}
}
void build(){
queue<int> q;
for(int i=0;i<26;i++){
if(tr[0][i]) q.push(tr[0][i]),insert(0,tr[0][i]);
}
while(!q.empty()){
int now=q.front();q.pop();
for(int i=0;i<26;i++){
if(tr[now][i]) fail[tr[now][i]]=tr[fail[now]][i],q.push(tr[now][i]),insert(fail[tr[now][i]],tr[now][i]);
else tr[now][i]=tr[fail[now]][i];
}
}
}
inline int lowbit(int x){
return x&(-x);
}
void update(int x,int v){
for(int i=x;i<maxn;i+=lowbit(i)) d[i]+=v;
}
int query(int x){
int res=0;
for(int i=x;i>=1;i-=lowbit(i)) res+=d[i];
return res;
}
void work(){
int len=s.length(),now=0,cntq=1;
for(int i=0;i<len;i++){
if(s[i]=='B'){
update(dfn[now],-1);
now=fa[now];
}
else if(s[i]=='P'){
while(cntq<=n&&num[q[cntq].y]==now){
int x1=query(dfn[num[q[cntq].x]]+siz[num[q[cntq].x]]-1),x2=query(dfn[num[q[cntq].x]]-1);
q[cntq].ans=x1-x2;
cntq++;
}
}
else{
now=tr[now][s[i]-'a'];
update(dfn[now],1);
}
}
}
int main(){
ios::sync_with_stdio(false);
memset(p,-1,sizeof(p));
cin>>s;
inserts();
build();
dfs(0);
cin>>n;
for(int i=1;i<=n;i++){
q[i].id=i;
cin>>q[i].x>>q[i].y;
}
sort(q+1,q+n+1,cmp1);
work();
sort(q+1,q+n+1,cmp2);
for(int i=1;i<=n;i++) cout<<q[i].ans<<endl;
return 0;
}