原题
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有 26个小写英文字母和’B’、’P’两个字母。 经阿狸研究发现,这个打字机是这样工作的:
输入小写字母,打字机的一个凹槽中会加入这个字母(按 P 前凹槽中至少有一个字母)。
按一下印有’B’的按键,打字机凹槽中最后一个字母会消失。
按一下印有’P’的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失(保证凹槽中至少有一个字母) 。
例如,阿狸输入 aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从 1开始顺序编号,一直到 n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。 阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
题解
比较几个匹配串,一般来说AC自动机是一个很好的选择。
根据输入的第一个长字符串,考虑P和B表示什么。
建造Trie的时候,P表示标记,B表示回到自己的父亲,小写字母表示向下走。
但是有这么多组询问,怎么用很短的时间解决掉他们呢?
题目条件:
①被打印的字符串是有序的,即Trie上的一个节点表示被打印的字符串的一个区间[l,r]。
②问一个串在另一个串中出现了几次。
相应对策:
那么再跑一遍Trie,就可以解决掉[l,r]区间的问题。
只需要在进来这个点时在数据结构中+1,出去时-1即可。
问次数,就是问在fail树上,根节点到某个其子树种节点的路径上,有几个+1。
代码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 100010
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
int id,u,v;
};note qu[N];
struct note1{
int to,next;
};note1 edge[N];
int tot,head[N],ans[N];
int i,j,k,l,n,m,x,gs,cs,wz,y;
int c[N],u,v;
int tr[N][26],fail[N],bz[N],pre[N];
int dfn[N],T,fa[N];
int val[N],siz[N];
char s[N],ch;
queue<int>Q;
int read(){
int fh=1,res=0;char ch;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
return fh*res;
}
void write(int x){
if(x>9)write(x/10);
P(x%10+'0');
}
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
int lowbit(int x){return x&(-x);}
void ins(int x,int delta){
for(;x<=gs+1;x+=lowbit(x))c[x]+=delta;
}
int query(int x){
int res=0;
for(;x;x-=lowbit(x))res+=c[x];
return res;
}
void dfs(int x){
dfn[x]=++T;
siz[x]=1;
int i;
for(i=head[x];i;i=edge[i].next)
if(fa[x]!=edge[i].to){
fa[edge[i].to]=x;
dfs(edge[i].to);
siz[x]+=siz[edge[i].to];
}
}
bool cmp(note x,note y){return x.v<y.v||(x.v==y.v&&x.u<y.u);}
int main(){
ch=getchar();
while((ch>='a'&&ch<='z')||ch=='B'||ch=='P')s[++l]=ch,ch=getchar();
n=read();
fo(i,1,n){
u=read(),v=read();
qu[i].id=i;qu[i].u=u;qu[i].v=v;
}
k=0;gs=0;pre[0]=-1;
fo(i,1,l){
ch=s[i];
if(ch>='a'&&ch<='z'){
x=s[i]-'a';
if(tr[k][x])k=tr[k][x];
else{
tr[k][x]=++gs;
val[gs]=x;
pre[gs]=k;
k=gs;
}
} else
if(ch=='B')k=pre[k];else bz[++cs]=k;
}
fail[0]=-1;
Q.push(0);
while(!Q.empty()){
x=Q.front();Q.pop();
fo(i,0,25){
j=tr[x][i];
if(!j)continue;
Q.push(j);
k=fail[x];
while(~k&&!tr[k][i])k=fail[k];
if(k==-1)fail[j]=0;else fail[j]=tr[k][i];
}
}
fo(i,1,gs)lb(fail[i],i);
dfs(0);
sort(qu+1,qu+n+1,cmp);
k=0;y=1;
ins(1,1);
fo(i,1,l){
ch=s[i];
if(ch>='a'&&ch<='z'){
x=s[i]-'a';
k=tr[k][x];
ins(dfn[k],1);
} else
if(ch=='B'){
ins(dfn[k],-1);
k=pre[k];
}
else{
wz++;
while(wz==qu[y].v && y<=n){
u=bz[qu[y].u];
ans[qu[y].id]=query(dfn[u]+siz[u]-1)-query(dfn[u]-1);
y++;
}
}
}
ins(1,-1);
fo(i,1,n)write(ans[i]),P('\n');
return 0;
}