AC自动机:BZOJ 2434 阿狸的打字机

2434: [Noi2011]阿狸的打字机

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1834  Solved: 1053
[Submit][Status][Discuss]

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

 
  这题我很久以前见到过,当时没敢动手,现在学了AC自动机后,果断拿来练手了。
  题意很简单,可以离线。
  这里在建完fail树后须将fail边反向,建成一棵fail树,如果能A到B有条边,那么代表trie树上到A的字符串是到B的字符串的后缀,这时来一遍DFS,记录每一个点的时间戳,即一个时间段,be[i]指i点自己的编号,也指其开始,en[i]指其结束。
  对于一个节点,fail树上的子树中,所有节点的fail都直接或间接的连向它,指它是那些的子串,被他们包含,而用时间戳可以迅速知道一个点是否是其子树。
  之后用离线做法处理答案,用bit维护。
 
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 #include <algorithm>
  6 using namespace std;
  7 const int maxn=1e5+10;
  8 char S[maxn];
  9 int Query[maxn][2],ans[maxn],cntQ;
 10 struct A_Cautomation{
 11     int ch[maxn][27],fail[maxn],end[maxn],fa[maxn],ID[maxn],cnt,root,cont;
 12     int fir[maxn],nxt[maxn],to[maxn],cot;
 13     int be[maxn],en[maxn],sjc;
 14     void Init()
 15     {
 16         memset(ch,0,sizeof(ch));
 17         memset(fail,0,sizeof(fail));
 18         memset(end,0,sizeof(end));
 19         sjc=cot=cnt=cont=root=0;
 20     }
 21     void Insert()
 22     {
 23         scanf("%s",S);
 24         int len=strlen(S),node=root;
 25         for(int i=0;i<len;i++)
 26         {
 27             if(S[i]>='a'&&S[i]<='z'){
 28                 if(ch[node][S[i]-'`']){
 29                     node=ch[node][S[i]-'`'];
 30                 }
 31                 else{
 32                     fa[++cnt]=node;
 33                     node=ch[node][S[i]-'`']=cnt;
 34                 }
 35             }
 36             else{
 37                 if(S[i]=='B'){
 38                     node=fa[node];
 39                 }
 40                 else{
 41                     end[node]=++cont;
 42                     ID[cont]=node;
 43                 }    
 44             }
 45         }
 46     }
 47     void Build()
 48     {
 49         queue<int>q;
 50         for(int i=1;i<=26;i++){
 51             if(ch[root][i]){
 52                 fail[ch[root][i]]=root;
 53                 q.push(ch[root][i]);
 54             }
 55             else 
 56                 ch[root][i]=root;
 57         }
 58         while(!q.empty())
 59         {
 60             int node=q.front();q.pop();
 61             for(int i=1;i<=26;i++){
 62                 if(ch[node][i]){
 63                     fail[ch[node][i]]=ch[fail[node]][i];
 64                     q.push(ch[node][i]);
 65                 }
 66                 else{
 67                     ch[node][i]=ch[fail[node]][i];
 68                 }
 69             }
 70         }
 71     }
 72     
 73     void addedge(int a,int b)
 74     {nxt[++cot]=fir[a];fir[a]=cot;to[cot]=b;}
 75     
 76     void DFS(int node)
 77     {
 78         be[node]=++sjc;
 79         for(int i=fir[node];i;i=nxt[i])
 80         DFS(to[i]);
 81         en[node]=sjc;
 82     }
 83     
 84     void BuildTree()
 85     {
 86         for(int i=1;i<=cnt;i++)
 87             addedge(fail[i],i);
 88         
 89         DFS(root);        
 90     }
 91     
 92     int bit[maxn];
 93     void change(int k,int x)
 94     {
 95         while(k<=100000)
 96         {
 97             bit[k]+=x;
 98             k+=k&(-k);
 99         }
100     }
101     
102     int Quer(int k)
103     {
104         int ret=0;
105         while(k)
106         {
107             ret+=bit[k];
108             k-=k&(-k);
109         }
110         return ret;
111     }
112     
113     void Solve()
114     {
115         memset(fir,0,sizeof(fir));cot=0;
116         memset(bit,0,sizeof(bit));
117         for(int i=1;i<=cntQ;i++)
118         Query[i][0]=ID[Query[i][0]],
119         Query[i][1]=ID[Query[i][1]],
120         addedge(Query[i][1],Query[i][0]);
121         
122         int len=strlen(S),node=root;
123         for(int i=0;i<len;i++)
124         {
125             if(S[i]>='a'&&S[i]<='z'){
126                 node=ch[node][S[i]-'`'];
127                 change(be[node],1);
128             }
129             else{
130                 if(S[i]=='B'){
131                     change(be[node],-1);
132                     node=fa[node];
133                 }
134                 else{
135                     for(int i=fir[node];i;i=nxt[i]){
136                         ans[i]=Quer(en[to[i]])-Quer(be[to[i]]-1);
137                     }
138                 }    
139             }
140         }
141         
142         for(int i=1;i<=cntQ;i++)
143         printf("%d\n",ans[i]);
144     }
145 }AC;
146 
147 int main()
148 {
149     AC.Init();
150     AC.Insert();
151     AC.Build();
152     AC.BuildTree();
153     
154     int Q;
155     scanf("%d",&Q);
156     while(Q--)
157         scanf("%d%d",&Query[cntQ][0],&Query[++cntQ][1]);
158     
159     AC.Solve();    
160     return 0;
161 }

 

posted @ 2016-02-15 22:12  TenderRun  阅读(348)  评论(0编辑  收藏  举报