• 洛谷 P2414 [NOI2011]阿狸的打字机(Fail树 || DFS序 || 树状数组)


    题目链接:https://www.luogu.com.cn/problem/P2414

    由于Fail指针指向 “这个串的最长后缀”。而指向的那个点又是某个字符串的前缀。所以后缀的前缀是子串。 

     然后可以直接建出Fail树,建树时,如果$'B'$,那么就返回到这个节点的父亲,如果$'P'$,就把这一组存下来,vis和id是互为映射。

    一遍DFS,处理出DFS序,然后便可以进行区间操作了。

    用离线处理的方法,把每一组按照y排序,那么可以处理每一组询问,把同一种询问保存在一起。

    比如询问第1个打印的字符串在第3个出现了几次,询问第2个字符串在第3个出现了几次,就可以把两个询问合并,变成:第3个打印的字符串中出现了几次第1个,几个第2个。

    然后考虑每一个的贡献,可以用树状数组维护,如果有一个小写字母,那么便区间+1,每'B'一次,则区间-1。每'P'一次,则区间询问一次,求出答案,并离线记录。

    AC代码:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<queue>
      6 using namespace std;
      7 const int N=1000000+10;
      8 char str[N];
      9 int ch[N][26],fail[N],vis[N],fa[N];
     10 int cnt,num,dfn,tot;
     11 int L[N],R[N],head[N],id[N],ans[N],c[N];
     12 struct node{
     13     int to,next;
     14 }edge[N*2];
     15 struct Node{
     16     int x,y;
     17     int pos; 
     18 }q[N];
     19 bool cmp(Node aa,Node bb){
     20     return aa.y<bb.y;
     21 }
     22 void init(){
     23     num=dfn=cnt=tot=0;
     24     memset(vis,0,sizeof(vis));
     25     memset(head,-1,sizeof(head));
     26 }
     27 void add(int u,int v){
     28     edge[tot].to=v;
     29     edge[tot].next=head[u];
     30     head[u]=tot++;
     31 }
     32 void get_fail(){
     33     queue<int> q;
     34     for(int i=0;i<26;i++){
     35         if(ch[0][i]){
     36             add(0,ch[0][i]);
     37             q.push(ch[0][i]);
     38         }
     39     }
     40     while(!q.empty()){
     41         int u=q.front();q.pop();
     42         for(int i=0;i<26;i++){
     43             if(ch[u][i]){
     44                 fail[ch[u][i]]=ch[fail[u]][i];
     45                 q.push(ch[u][i]);
     46                 add(fail[ch[u][i]],ch[u][i]);
     47             }
     48             else ch[u][i]=ch[fail[u]][i];
     49         }
     50     }
     51 }
     52 void DFS(int u,int fa){
     53     L[u]=++dfn;
     54     for(int i=head[u];i!=-1;i=edge[i].next){
     55         int v=edge[i].to;
     56         if(v==fa) continue;
     57         DFS(v,u);
     58     }
     59     R[u]=dfn;
     60 }
     61 int lowbit(int x){
     62     return x&(-x);
     63 }
     64 void addval(int x,int val){
     65     while(x<=dfn){
     66         c[x]+=val;
     67         x+=lowbit(x);
     68     }
     69 }
     70 int query(int x){
     71     int ans=0;
     72     while(x){
     73         ans+=c[x];
     74         x-=lowbit(x);
     75     }
     76     return ans;
     77 }
     78 int main(){
     79     scanf("%s",str);
     80     int len=strlen(str);
     81     init();
     82     int u=0;
     83     for(int i=0;i<len;i++){
     84         if(str[i]>='a'&&str[i]<='z'){
     85             int id=str[i]-'a';
     86             if(!ch[u][id]) ch[u][id]=++cnt;
     87             fa[cnt]=u;
     88             u=ch[u][id];
     89         }
     90         else if(str[i]=='B') u=fa[u];
     91         else vis[u]=++num,id[num]=u;
     92     }
     93     get_fail();
     94     DFS(0,-1);
     95     int n;
     96     scanf("%d",&n);
     97     for(int i=1;i<=n;i++){
     98         scanf("%d%d",&q[i].x,&q[i].y);
     99         q[i].pos=i; 
    100     }
    101     sort(q+1,q+n+1,cmp);
    102     num=0;
    103     int j=0,root=0;
    104     for(int i=0;i<len;i++){
    105         if(str[i]=='B') addval(L[root],-1),root=fa[root];
    106         else if(str[i]=='P'){
    107             num++;
    108             while(j<n&&q[j+1].y==num){
    109                 j++;
    110                 int v=id[q[j].x];
    111                 ans[q[j].pos]=query(R[v])-query(L[v]-1);
    112             }
    113         }
    114         else{
    115             int id=str[i]-'a';
    116             root=ch[root][id];
    117             addval(L[root],1);
    118         }
    119     }
    120     for(int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    121     return 0;
    122 }
    AC代码
  • 相关阅读:
    单词接龙
    洛谷 P1015 回文数
    洛谷 P1012 拼数
    codevs 2780 ZZWYYQWZHZ
    专项练习之字符串
    模拟题1
    专项训练之线段树
    复习题之求后序遍历
    复习题之二叉树的遍历
    Hdu 3037 Saving Beans(Lucus定理+乘法逆元)
  • 原文地址:https://www.cnblogs.com/New-ljx/p/12432574.html
Copyright © 2020-2023  润新知