1. 程式人生 > >刷題總結——字符串(ssoj)

刷題總結——字符串(ssoj)

sso cnblogs 其中 ctime 題解 += 不用 const void

題目:

給定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; }

刷題總結——字符串(ssoj)