刷题总结——字符串(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;
}
原文地址:https://www.cnblogs.com/AseanA/p/7677782.html