• 刷题总结——字符串(ssoj)


    题目:

    给定n个小的字符串T和一个大的字符串S,先输出T总共再S中出现了多少次

    然后q个询问···每次修改S上的一个字母,然后再次输出上述答案···

    n小于1000,q<200000,T的总长度和S的长度都小于100000;

    题解:

    我们可以发现,每次修改位置P,那么S影响的范围只有在P-MAX到P+MAX的范围,其中MAX为T的最长长度····所以将这一范围的S跑一边AC自动机··然后更新答案即可··

    这道题也让我发现我做AC自动机以来一直有的一个不好的习惯··每次求出现次数都是暴力跳fail指针,这样再这道题里直接T····

    其实再我们bfs构建fail指针时,设u的指针为v,我们可以直接tree[u].cnt+=tree[v].cnt,这样每次加的时候直接加上一个节点cnt就可以了··不用暴力跳fail···代码:

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    using namespace std;
    queue<int>que;
    const int N=100005;
    struct node
    {
      int son[26],cnt,fail;
      void clear()
      {
        memset(son,0,sizeof(son));
        cnt=fail=0;
      }
    }tree[N];
    int n,m,T,tot,maxx=0;
    char s[N],t[5];
    inline int R()
    {
      char c;int f=0;
      for(c=getchar();c<'0'||c>'9';c=getchar());
      for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';  
      return f;
    }
    int buf[1024];
    inline void W(int x){
        if(!x){putchar('0');return ;}
        if(x<0){putchar('-');x=-x;}
        while(x) buf[++buf[0]]=x%10,x/=10;
        while(buf[0]) putchar(buf[buf[0]--]+48);
        return ;
    }
    
    inline void build()
    {
      int po=1;
      int len=strlen(s);maxx=max(maxx,len);
      for(int i=0;i<len;i++)
      {
        if(!tree[po].son[s[i]-'a'])
          tree[tree[po].son[s[i]-'a']=++tot].clear();
        po=tree[po].son[s[i]-'a'];
      }
      tree[po].cnt++;
    }
    inline void buildfail()
    {
      que.push(1);
      while(!que.empty())
      {
        int u=que.front();que.pop();
        for(int i=0;i<26;i++)
        {
          int v=tree[u].fail;
          while(!tree[v].son[i])  v=tree[v].fail;
          v=tree[v].son[i];int w=tree[u].son[i];
          if(w)  tree[w].fail=v,que.push(w),tree[w].cnt+=tree[v].cnt; 
          else tree[u].son[i]=v;
        }
      }
    }
    int main()
    {
      //freopen("string.in","r",stdin);
      //freopen("string.out","w",stdout);
      n=R(),m=R();
      for(int i=0;i<26;i++)
        tree[0].son[i]=1;
      tree[tot=1].clear();
      for(int i=1;i<=n;i++)
      {
        scanf("%s",s);   
        build();
      }
      buildfail();
      scanf("%s",s);
      int len=strlen(s),a;
      int now=1,ans=0;
      for(int i=0;i<len;i++)
      {
        now=tree[now].son[s[i]-'a'];
        ans+=tree[now].cnt;
      }
      W(ans),putchar('
    ');
      while(m--)
      {  
          a=R();scanf("%s",t);
        int now=1,ans1=0,ans2=0;
        for(int i=max(0,a-maxx);i<=min(a+maxx-1,len-1);i++)
        {
          now=tree[now].son[s[i]-'a'];                   
          ans1+=tree[now].cnt;
        }
        ans-=ans1;
        s[a-1]=t[0];now=1;
        for(int i=max(0,a-maxx);i<=min(a+maxx-1,len-1);i++)
        {
          now=tree[now].son[s[i]-'a'];
          ans2+=tree[now].cnt;
        }
        ans+=ans2;
        W(ans),putchar('
    ');
      }
      return 0;
    }
  • 相关阅读:
    「十二省联考2019」 春节十二响
    「八省联考2018」 劈配
    斯特林数
    「POJ2505」A multiplication game [博弈论]
    [luogu2048] [bzoj2006] [NOI2010] 超级钢琴 题解
    [HNOI2002]-洛谷2234-营业额统计-Treap
    平衡树Treap模板与原理
    KMP算法讲解
    高斯消元--模板,原理
    第一篇博客!!
  • 原文地址:https://www.cnblogs.com/AseanA/p/7677782.html
Copyright © 2020-2023  润新知