这是一个句子测试

1
5
2016
0

BZOJ2434【NOI2011阿狸的打字机】

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

Source

【题解】

isprogrammer炸掉了一个星期真是不爽

做这道题让窝感觉没学过trie图。。。。。

首先要用黑暗的方法构出trie树,即按照读入顺序扫下来,那么有三种情况:

1、碰到字母,新建一个子节点(如果已存在就不用新建),进入该子节点。

2、碰到P,那么打个标记。

3、碰到B,回到父亲节点。

然后求出每个节点的fail,那么询问x在y中出现多少次,只要求root~y中有多少点沿fail能走到x。

那么构出fail树,问题就转化为x的子树中有多少个是root~y中的点。

考虑dfs序,那么求子树和的问题就转化为求片段和,可以用树状数组维护。

对于一个串y,将root~y的点的dfs序插入树状数组中,然后处理所有与y有关的询问就阔以辣!

最后的处理还是可以直接扫描读入的串:

1、碰到字母,将子节点的dfs序加入树状数组,进入该子节点。

2、碰到P,处理询问。

3、碰到B,回到父亲节点。

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=100010;
int m,cnt,u,id,i,x,y,edgenum,Edgenum,T;
char s[M];
int pos[M],fa[M],head[M],vet[M],next[M],Head[M],Vet[M],Next[M],tree[2*M],fail[M],h[M],l[M],r[M],ans[M];
int trie[M][26];
void addedge(int x,int y){
    vet[++edgenum]=y;
    next[edgenum]=head[x];
    head[x]=edgenum;
}
void Addedge(int x,int y){
    Vet[++Edgenum]=y;
    Next[Edgenum]=Head[x];
    Head[x]=Edgenum;
}
void update(int x,int y){
    for (int i=x;i<=T;i+=i&-i)tree[i]+=y;
}
int query(int x){
    int ans=0;
    for (int i=x;i;i-=i&-i)ans+=tree[i];
    return ans;
}
void bfs(){
    int l=1,r=1;
    h[l]=1,fail[1]=0;
    while (l<=r){
        int u=h[l];
        for (int i=0;i<26;i++)
            if (trie[u][i]){
                int v=trie[u][i];
                if (u==1)fail[v]=1;else fail[v]=trie[fail[u]][i];
                h[++r]=v;
            }else trie[u][i]=trie[fail[u]][i];
        l++;
    }
}
void dfs(int u){
    l[u]=++T;
    for (int e=head[u];e;e=next[e])dfs(vet[e]);
    r[u]=++T;
}
int main(){
    scanf("%s",s);
    scanf("%d",&m);
    int n=strlen(s);
    cnt=1,u=1,id=0;
    for (i=0;i<26;i++)trie[0][i]=1;
    for (i=0;i<n;i++){
        if (s[i]-'a'>=0){
            if (!trie[u][s[i]-'a'])trie[u][s[i]-'a']=++cnt,fa[cnt]=u;
            u=trie[u][s[i]-'a'];
        }else if (s[i]=='P')pos[++id]=u;else u=fa[u];
    }
    bfs();
    for (i=1;i<=cnt;i++)addedge(fail[i],i);
    dfs(0);
    for (i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        Addedge(y,x);
    }
    u=1,id=0;update(l[1],1);
    for (i=0;i<n;i++){
        if (s[i]-'a'>=0)u=trie[u][s[i]-'a'],update(l[u],1);
            else if (s[i]=='P'){
                id++;
                for (int e=Head[id];e;e=Next[e]){
                    int v=pos[Vet[e]];
                    ans[e]=query(r[v])-query(l[v]-1);
                }   
            }else update(l[u],-1),u=fa[u];
    }
    for (i=1;i<=m;i++)printf("%d\n",ans[i]);
}

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com