• 【dfs序+AC自动机+树状数组】BZOJ2434-[Noi2011]阿狸的打字机


    【题目大意】

    输入一个字符串,其中:(1)a..z:在字符串末尾添加当前字符(2)P:输出当前字符串(3)B:从当前字符串末尾删去一个字符。

    给出m组查询,输出第i个输出的字符串在第j个输出的字符串内出现了几次。

    【思路】

    卡了好久,写完不想调试,调试完不想提交,期间颓颓颓地弄了下博客的界面,弄成了粉嫩少女风(划掉)。结果提交完1A有点迷醉迷醉的……

    首先我们要借用BZOJ3172的结论:←戳这里,这个结论66666,是本次解题的关键。

    “建立AC自动机,对于路径上的每一个点sum++,表示出现的次数。fail指针指向的后缀,如果从fail指针指向的点开始方向建立fail树,其子树的sum之和就等于以它作为后缀的串的总数,相当于它在文章中出现的个数。”

    显然我们要把m组询问(i,j)调换位置,同一组j,对i建立一个链表存放。为什么要这么做呢?先继续往下看。

    首先,我们建立一个AC自动机,并建立fail树。这里和一般的建立有点区别,因为有删除操作,可以用一个栈来维护当前位于Trie的位置,如果B删除就弹出栈顶,如果为字母就建立新节点并压入栈中,如果是P就在当前位置打上ed的标记,表示这是第ed次打印的字符终止位置。

    由于树中节点和子树的dfs序是连续的,我们跑一次dfs记录下fail树上每个点的dfs序,记录下第i个输出字符串,它的末尾节点及其子树在dfs序中的start和end位置。

    最后,重新跑一次Trie,和先前一样用栈维护。如果遇到B,就将当前节点-1,弹出栈顶;遇到字母就将当前节点+1;如果遇到P,说明现在恰巧输出了第j个字符串,枚举每一个查询中的i,查询结果=当前i对应的节点和它子树之和。

    没错,这是一个单点修改,区间求和,可以用树状数组来维护一下,每个节点在树状数组中的位置就等于它的dfs序。那么当前i对应的节点及其子树之和=sum[start[i]..end[i]],搞定!

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<queue>
      7 #define lnum 26
      8 using namespace std;
      9 const int MAXN=100000+50;
     10 int  ppos[MAXN];//第i个P对应的栈顶位置编号
     11 char str[MAXN];
     12 int m,len,step,cnt=0,e[MAXN],start[MAXN],end[MAXN],ans[MAXN];
     13 struct ACauto
     14 {
     15     ACauto* next[lnum];
     16     ACauto* fail;
     17     int id,ed,order; 
     18     ACauto()
     19     {
     20         for (int i=0;i<lnum;i++) next[i]=NULL;
     21         fail=NULL;
     22         id=++cnt;
     23     }
     24 };
     25 struct node
     26 {
     27     int to,id;
     28 }; 
     29 ACauto* rt=new ACauto();
     30 ACauto* p[MAXN];//编号为i的节点指向的位置
     31 vector<node> Q[MAXN];
     32 vector<int> E[MAXN];
     33 
     34 void addedge(int u,int v)
     35 {
     36     E[u].push_back(v);
     37 }
     38 
     39 int lowbit(int x)
     40 {
     41     return (x&(-x));
     42 }
     43 
     44 void modify(int p,int x)
     45 {
     46     int i=p;
     47     while (i<=len)
     48     {
     49         e[i]+=x;
     50         i+=lowbit(i);
     51     }
     52 }
     53 
     54 int sum(int p)
     55 {
     56     int s=0;
     57     int i=p;
     58     while (i>0)
     59     {
     60         s+=e[i];
     61         i-=lowbit(i);
     62     }
     63     return s;
     64 }
     65 
     66 void init()
     67 {
     68     scanf("%s",str);
     69     len=strlen(str);
     70     int top=0,n=0;
     71     ACauto* stack[MAXN];
     72     stack[++top]=p[1]=rt;//不要忘记给p[1]赋值 
     73     for (int i=0;i<len;i++)
     74     {
     75         if (str[i]=='P') 
     76         {
     77             stack[top]->ed=++n;
     78             ppos[n]=stack[top]->id;
     79         }
     80             else if (str[i]=='B') top--;
     81                 else
     82                 {
     83                     int index=str[i]-'a';
     84                     if (stack[top]->next[index]==NULL) 
     85                     {
     86                         stack[top]->next[index]=new ACauto();
     87                         p[cnt]=stack[top]->next[index];
     88                     }
     89                     stack[++top]=stack[top-1]->next[index];
     90                 }
     91     }
     92     
     93     scanf("%d",&m);
     94     for (int i=0;i<m;i++)
     95     {
     96         int x,y;
     97         scanf("%d%d",&x,&y);
     98         Q[y].push_back((node){ppos[x],i});
     99     }
    100 } 
    101 
    102 void buildfail()
    103 {
    104     queue<ACauto*> que;
    105     que.push(rt);
    106     while (!que.empty())
    107     {
    108         ACauto* head=que.front();que.pop();
    109         for (int i=0;i<lnum;i++)
    110         {
    111             if (head->next[i]!=NULL)
    112             {
    113                 if (head==rt)
    114                 {
    115                     head->next[i]->fail=rt;
    116                     addedge(rt->id,head->next[i]->id);
    117                 }
    118                 else
    119                 {
    120                     ACauto* tmp=head->fail;
    121                     while (tmp!=NULL)
    122                     {
    123                         if (tmp->next[i]!=NULL)
    124                         {
    125                             head->next[i]->fail=tmp->next[i];
    126                             addedge(tmp->next[i]->id,head->next[i]->id);
    127                             break;
    128                         }
    129                         else tmp=tmp->fail;
    130                     }
    131                     if (tmp==NULL) 
    132                     {
    133                         head->next[i]->fail=rt;
    134                         addedge(rt->id,head->next[i]->id);
    135                     }
    136                 }
    137                 que.push(head->next[i]);
    138             }
    139         }
    140     }
    141 }
    142 
    143 void dfs(int pos)
    144 {
    145     ACauto* tmp=p[pos];
    146     tmp->order=++step;
    147     if (tmp->ed) start[tmp->ed]=step;
    148     for (int i=0;i<E[pos].size();i++) dfs(E[pos][i]);
    149     if (tmp->ed) end[tmp->ed]=step;
    150 }
    151 
    152 void query()
    153 {
    154     memset(e,0,sizeof(e));
    155     int top=0,n=0;
    156     ACauto* stack[MAXN];
    157     stack[++top]=rt;
    158     for (int i=0;i<len;i++)
    159     {
    160         if (str[i]=='P')
    161         {
    162             n++;
    163             for (int i=0;i<Q[n].size();i++)
    164             {
    165                 ACauto* to=p[Q[n][i].to];
    166                 ans[Q[n][i].id]=sum(end[to->ed])-sum(start[to->ed]-1);
    167             }
    168         }
    169         else if (str[i]=='B')
    170         {
    171             modify(stack[top]->order,-1);
    172             top--;
    173         }
    174         else
    175         {
    176             int index=str[i]-'a';
    177             stack[++top]=stack[top-1]->next[index];
    178             modify(stack[top]->order,1);
    179         }
    180     }
    181 }
    182 
    183 void printans()
    184 {
    185     for (int i=0;i<m;i++) printf("%d
    ",ans[i]);
    186 }
    187 
    188 int main()
    189 {
    190     init();
    191     buildfail();
    192     dfs(rt->id);
    193     query();
    194     printans();
    195     return 0;
    196 }
  • 相关阅读:
    西南民族大学第十二届程序设计竞赛(同步赛) A.逃出机房 (bfs)
    2020-2021 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules) D. Firecrackers (贪心,二分)
    2020-2021 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules) C. Berpizza (STL)
    2020 ICPC Asia Taipei-Hsinchu Regional Problem H Optimization for UltraNet (二分,最小生成树,dsu计数)
    2020 ICPC Asia Taipei-Hsinchu Regional Problem B Make Numbers (dfs搜索)
    Codeforces Round #689 (Div. 2, based on Zed Code Competition) E. Water Level (贪心好题)
    Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3) C. Peaceful Rooks (思维,dsu找环)
    PAT五一线上模拟测试赛
    【PAT五一线上模拟测试赛】7-3 垃圾分类 (20分) Java和Python
    【PAT五一线上模拟测试赛】7-2 三阶幸福数 (20分) Pyton+Java
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5706667.html
Copyright © 2020-2023  润新知