刷题总结——字符串(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('\n'); 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('\n'); } return 0; }