CF914F Substrings in a String
阿新 • • 發佈:2020-07-09
題意:給一個串\(S\),有\(q\)次操作:
1 i c表示將\(i\)位置的字元修改為\(c\);2 l r t表示求\(s_{l},s_{l+1},\cdots s_r\)中\(t\)串的出現次數。
\(|S|,q,\sum |t| \leq 10^5\)。
題解:不難想到暴力kmp匹配,單次查詢的時間複雜度是\(O(|S|+|t|)\)。發現\(|t|\)較小時這樣做很不划算,因此我們可以考慮根號分治。
當\(|t|\)較小時,如果我們對\(S\)分塊,那麼\(t\)只會有兩種情況:完全在塊內,或者在兩個塊之間。
對於整塊,我們對每個塊內的字串都建立SAM,有修改就打個標記,查詢時拍扁重建。由於修改次數最多\(n\)
對於散塊,直接kmp即可。
對於\(t\)在兩個塊之間的情況,我們只需要考慮左端點在上一個塊,右端點在當前塊的位置,因此直接kmp的複雜度也是\(O(|t|)\)的。
時間複雜度:\(O(n \sqrt n)\)。
程式碼:
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } const int N=316; char c[101000],t[101000],cc; int n,m,sum,T,ln,ans,a[101000],b[101000]; int sit,X,Y,W; struct SAM{ int p,q,las,tot,cur,cle,len[660],link[660],ch[660][26],cnt[660],buc[660],sa[660],lft,rit,v; I clear(int x){ len[x]=link[x]=cnt[x]=0; F(i,0,25)ch[x][i]=0; } I insert(int x){ cur=++tot;clear(tot); len[cur]=len[las]+1;p=las;las=cur;cnt[cur]=1; while(p&&!ch[p][x])ch[p][x]=cur,p=link[p]; if(!p)return link[cur]=1,void(); q=ch[p][x];if(len[p]+1==len[q])return link[cur]=q,void(); cle=++tot;clear(cle);len[cle]=len[p]+1;link[cle]=link[q];F(i,0,25)ch[cle][i]=ch[q][i]; while(p&&ch[p][x]==q)ch[p][x]=cle,p=link[p]; link[q]=link[cur]=cle; } I build(){ v=1;tot=las=1;clear(1); F(i,lft,rit)insert(a[i]); F(i,1,tot)buc[i]=0; F(i,1,tot)buc[len[i]]++; F(i,1,tot)buc[i]+=buc[i-1]; FOR(i,tot,1)sa[buc[len[i]]--]=i; FOR(i,tot,2)cnt[link[sa[i]]]+=cnt[sa[i]]; } I solve(){ if(!v)build(); re p=1,val; F(i,1,ln){ val=t[i]-'a'; if(!ch[p][val])return; p=ch[p][val]; } ans+=cnt[p]; } }s[330]; int w[101000],nt[101000],k; I init(){ F(i,1,ln)w[i]=t[i]-'a';w[ln+1]=-1; nt[1]=0;k=0; F(i,2,ln){ while(k&&w[k+1]!=w[i])k=nt[k]; if(w[k+1]==w[i])k++; nt[i]=k; } // F(i,1,ln)cout<<nt[i]<<" ";cout<<endl; } I kmp(int l,int r){ k=0;if(r-l+1<ln)return; // cout<<l<<" "<<r<<":"<<endl; F(i,l,r){ while(k&&w[k+1]!=a[i])k=nt[k]; if(w[k+1]==a[i])k++; if(k==ln)ans++,k=nt[k]; } } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>c+1;n=strlen(c+1);F(i,1,n)a[i]=c[i]-'a'; F(i,1,n)b[i]=((i-1)/N)+1;sum=b[n]; F(i,1,sum)s[i].lft=(i-1)*N+1,s[i].rit=min(i*N,n),s[i].v=0; cin>>m; while(m--){ cin>>sit>>X; if(sit==1){ cin>>cc;W=cc-'a'; a[X]=W;s[b[X]].v=0; } else{ T++; cin>>Y>>t+1;ln=strlen(t+1);ans=0; init();//if(T==104){F(i,1,ln)cout<<w[i]<<" ";cout<<endl;} if(ln>N)kmp(X,Y); else{ F(i,b[X]+1,b[Y]-1)s[i].solve(); if(b[X]==b[Y])kmp(X,Y); else{ kmp(X,s[b[X]].rit);kmp(s[b[Y]].lft,Y); if(ln>1){ F(i,b[X],b[Y]-1)kmp(max(X,s[i].rit-ln+2),min(Y,s[i+1].lft+ln-2)); } } } cout<<ans<<endl; } } return 0; }