• 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
    ",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 }

     

    尽最大的努力,做最好的自己!
  • 相关阅读:
    布局类组件介绍
    容器类组件介绍
    应用升级介绍
    Http组件的介绍
    Webview组件和HTML的介绍
    数据绑定介绍
    业界最具影响力MySQL精品文章荟萃(300篇)
    业界最有价值的 ASP.NET 博文汇总
    一个引号导致1个小时网站打不开
    这个世界从来没有任何一件工作叫“钱多、事少、离家近”
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5191441.html
Copyright © 2020-2023  润新知