BZOJ 2434 [Noi2011]阿狸的打字机

fail树+树状数组。。

2434: [Noi2011]阿狸的打字机

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 1046   Solved: 594
[ Submit][ Status]

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

Trie

[ Submit][ Status] 

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
#define ERR ;//puts("=======here========");
#define prt(k) ;//cout<<#k"="<<k<<" "
const int N=100400;
int ch[N][26],fail[N],fa[N];
int Size,root;
int newnode() { memset(ch[Size],-1,sizeof ch[0]);  Size++; return Size-1; }
void AC_init() { Size=0; root=newnode(); }
int pos[N];
void insert(char s[])
{
    int n=strlen(s),u=root,cur=0;  fa[0]=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='P') pos[++cur]=u;
        else {
            if(s[i]=='B') u=fa[u];
            else {
                int& tmp=ch[u][s[i]-'a'];   int t=u;
                u=(tmp!=-1)?tmp:tmp=newnode();  fa[u]=t;
            }
        }
    }
}
void AC_build()
{
    queue<int> q;
    for(int i=0;i<26;i++)
    {
        int& tmp=ch[root][i];
        if(tmp==-1) tmp=root;
        else { fail[tmp]=root; q.push(tmp); }
    }
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=0;i<26;i++)
        {
            int& tmp=ch[u][i];
            if(tmp==-1) tmp=ch[fail[u]][i];
            else { fail[tmp]=ch[fail[u]][i]; q.push(tmp); }
        }
    }
}
struct TREE {
int tree[N<<2];
TREE() { memset(tree,0,sizeof tree) ; }
inline int lowbit(int x) { return x&-x; }
void add(int p,int x)
{
    for(int i=p;i<N;i+=lowbit(i)) tree[i]+=x;
}
int sum(int p)
{
    int ret=0;
    for(int i=p;i>0;i-=lowbit(i)) ret+=tree[i];
    return ret;
}
int sum(int l,int r) { return sum(r)-sum(l-1); }
}T;
int Left[N],Right[N];
int tot;
vector<int> g[N];
void dfs(int u)
{
    Left[u]=++tot;
    for(int i=0;i<g[u].size();i++) dfs(g[u][i]);
    Right[u]=tot;
}
int ans[N];
struct data
{
    int x,id;
    data() {}
    data(int _x,int _id) { x=_x; id=_id; }
};
vector<data> q[N];
int Q;
char s[N];
void solve(char s[])
{
    int u=root,y=0;
    for(int i=0;s[i];i++)
    {
        if(s[i]=='P') {
            ++y;
            for(int j=0;j<q[y].size();j++)
            {   prt(j);
                int x=q[y][j].x;
                int id=q[y][j].id;
                x=pos[x];
                ans[id]=T.sum(Left[x],Right[x]);
            }
        }
        else if(s[i]=='B') {
            T.add(Left[u],-1);
            u=fa[u];
        }
        else {
            u=ch[u][s[i]-'a'];  ERR;
            T.add(Left[u],1);
        }
    }
}
int main()
{
    AC_init();
    scanf("%s",s);   insert(s);
    cin>>Q;
    for(int i=0;i<N;i++) q[i].clear();
    for(int i=1;i<=Q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        q[y].push_back(data(x,i));
        //  printf("id=%d x=%d y=%d\n",i,x,y);
    }
    AC_build();
   // for(int i=1;i<=3;i++) printf("pos[%d]=%d\n",i,pos[i]);
    for(int i=1;i<Size;i++) g[fail[i]].push_back(i);
    tot=0;
    dfs(root);
   // for(int i=0;i<Size;i++) printf("left[%d]=%d  right[%d]=%d \n",i,Left[i],i,Right[i]);
    solve(s);
    for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}
/**
aPaPBbP
3
1 2
1 3
2 3

*/


你可能感兴趣的:(数据结构,算法,字符串,ACM,AC自动机)