【Bzoj 2434】[NOI 2011] 阿狸的打字机

来源:互联网 发布:windows引导修复工具 编辑:程序博客网 时间:2024/05/17 08:34

Description

 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。 打字机上只有28个按键,分别印有26个小写英文字母和'B''P'两个字母。经阿狸研究发现,这个打字机是这样工作的:l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。例如,阿狸输入aPaPBbP,纸上被打印的字符如下:aaaab我们把纸上打印出来的字符串从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

aPaPBbP31 21 32 3

Sample Output

210

HINT

 1<=N<=10^51<=M<=10^5输入总长<=10^5

题解

经典的AC自动机+fail树+dfs序+树状数组,考试中会有点难想到用dfs序,写起来还是爽的飞起的

代码

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <queue>#include <ctime>#include <set>using namespace std;#define rep(i,l,r) for(i=l;i<=r;i++)#define ser(i,r,l) for(i=r;i>=l;i--)#define INF 100005#define inf 100000007typedef long long ll;priority_queue<int >QwQ;int l1,l=0,m,top=1,last=0,tot=1,cnt=0;int c[INF<<1],to[INF<<1],h[INF<<1],s[INF<<1],p[INF],fa[INF],t[INF][30],q[INF],fail[INF];int ans[INF],L[INF],R[INF];char s1[INF];int read(){    int k=0,f=1;    char ch;    while(ch<'0' || ch>'9'){        if(ch=='-')f=-1;        ch=getchar();    }    while(ch>='0' && ch<='9')k=(k<<1)+(k<<3)+ch-'0',ch=getchar();    return k*f;}int lowbit(int x){    return x&(-x);}void add(int x,int v){    int i,j,k;    for(i=x;i<=cnt;i+=lowbit(i))c[i]+=v;}int getsum(int x){    int i,j,k=0;    for(i=x;i;i-=lowbit(i))k+=c[i];    return k;}void hah(int x,int y){    to[++l]=y,h[l]=s[x],s[x]=l;}void Insert(){    int i,j,k,now=1,id=0;    rep(i,0,l1-1){        if(s1[i]=='P')p[++id]=now;        else if(s1[i]=='B')now=fa[now];        else {            k=s1[i]-'a'+1;            if(!t[now][k])t[now][k]=++tot,fa[tot]=now;            now=t[now][k];        }    }}void build_fail(){    int i,j,k,p;    q[0]=1,fail[1]=0;    while(last<top){        k=q[last++];        rep(i,1,26)         if(t[k][i]){            p=fail[k];            while(!t[p][i])p=fail[p];            fail[t[k][i]]=t[p][i];            q[top++]=t[k][i];         }    }}void dfs(int x){    int i,j,k;    L[x]=++cnt;    for(i=s[x];i;i=h[i])     dfs(to[i]);    R[x]=++cnt;}void solve(){    int i,j,k,now=1,id=0;    add(L[1],1);    rep(i,0,l1-1){        if(s1[i]=='P'){            id++;            for(j=s[id];j;j=h[j]){                k=p[to[j]];                ans[j]=getsum(R[k])-getsum(L[k]-1);            }        }        else if(s1[i]=='B')add(L[now],-1),now=fa[now];        else now=t[now][s1[i]-'a'+1],add(L[now],1);    }}void init(){    int i,j,k,x,y;    tot=1;    rep(i,1,26)t[0][i]=1;    scanf("%s",s1);    l1=strlen(s1);    Insert();    build_fail();    rep(i,1,tot)hah(fail[i],i);    dfs(0);    l=0;    memset(s,0,sizeof(s));    m=read();    rep(i,1,m){        x=read(),y=read();        hah(y,x);    }    solve();    rep(i,1,m)printf("%d\n",ans[i]);}void work(){    int i,j,k;}int main(){    init();    work();    return 0;}
1 0