Description
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。
经阿狸研究发现,这个打字机是这样工作的:
l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
Input
输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。
第二行包含一个整数m,表示询问个数。
接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。
Output
输出m行,其中第i行包含一个整数,表示第i个询问的答案。
Sample Input
aPaPBbP
3
1 2
1 3
2 3
Sample Output
2
1
0
HINT
1<=N<=10^5
1<=M<=10^5
输入总长<=10^5
Solution
AC自动机
不知道性质完全做不了
如果AC自动机中的两个串 \(p\) 和 \(s\) ,满足 \(p\) 在 \(s\) 中出现了 \(k\) 次,那么 \(k\) 等于 \(p\) 串结束点在fail树上的子树中有多少个节点属于串 \(s\)
维护树中一个节点的子树和,就随便搞了,我用的BIT
然后就可以离线了
首先把串按照题目含义建出AC自动机
然后getfail
对询问排序
开始算答案,重新跟着给的串走一遍,达到一个点,把它的贡献加入BIT,离开一个点则减去,那么BIT中保存的就一定是当前达到的点到根路径上的点的贡献
(注意,加贡献一定是加在这个点在fail树中的位置,而不是AC自动机上的位置)
所以如果当前到达了一个询问,就可以直接在BIT查答案了
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXM=100000+10;
int ch[MAXN][30],fail[MAXN],n,m,cnt,st[MAXN],e,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],nt,ans[MAXN],ed[MAXN],fa[MAXN],fl[MAXN],ps[MAXN];
char s[MAXN];
std::queue<int> q;
struct node{
int x,y,id;
inline bool operator < (const node &A) const {
return y<A.y;
};
};
node qs[MAXM];
struct BIT{
int C[MAXN];
inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int x,int k)
{
while(x<=nt)C[x]+=k,x+=lowbit(x);
}
inline int sum(int x)
{
int res=0;
while(x>0)res+=C[x],x-=lowbit(x);
return res;
}
};
BIT T;
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
}
inline void init()
{
int x=0;
for(register int i=0,lt=strlen(s);i<lt;++i)
if(s[i]=='P')fl[x]=++n,ps[n]=x;
else if(s[i]=='B')x=fa[x];
else if(!ch[x][s[i]-'a'+1])fa[cnt+1]=x,x=ch[x][s[i]-'a'+1]=++cnt;
else x=ch[x][s[i]-'a'+1];
}
inline void getfail()
{
for(register int i=1;i<=26;++i)
if(ch[0][i])q.push(ch[0][i]);
while(!q.empty())
{
int x=q.front();
q.pop();
for(register int i=1,y,z;i<=26;++i)
if(ch[x][i])
{
y=ch[x][i],z=fail[x];
while(z&&!ch[z][i])z=fail[z];
fail[y]=ch[z][i];
q.push(y);
}
}
}
inline void dfs(int x,int f)
{
st[x]=++nt;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f)continue;
else dfs(to[i],x);
ed[x]=nt;
}
inline void solve()
{
int x=0,nq=1;
for(register int i=0,lt=strlen(s);i<lt;++i)
{
if(s[i]=='P')
while(fl[x]==qs[nq].y)ans[qs[nq].id]=T.sum(ed[ps[qs[nq].x]])-T.sum(st[ps[qs[nq].x]]-1),++nq;
else if(s[i]=='B')T.add(st[x],-1),x=fa[x];
else x=ch[x][s[i]-'a'+1],T.add(st[x],1);
}
}
int main()
{
scanf("%s",s);
init();getfail();
for(register int i=1;i<=cnt;++i)insert(i,fail[i]),insert(fail[i],i);
read(m);
for(register int i=1;i<=m;++i)read(qs[i].x),read(qs[i].y),qs[i].id=i;
dfs(0,-1);
std::sort(qs+1,qs+m+1);
solve();
for(register int i=1;i<=m;++i)write(ans[i],'\n');
return 0;
}