hdu 4641 K-string(后缀自动机)
题目链接:hdu 4641 K-string
题意:
一开始给你一个字符串S,现在有m个操作。
1 x表示在当前字符串末端添加一个字符x。
2 表示查询当前出现次数超过k次的子串有多少个。
题解:
后缀自动机在线维护right集。
没插入一个字符,就沿着fail跳,如果当前节点大于等于k的就不用再跳了,显然之前的节点肯定已经大于等于k了。
然后一旦有新的节点等于k就记录一下当前新增加的子串个数。
1 #include<cstdio> 2 #include<cstring> 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4 #define mst(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 7 const int N=2e5+7,tyn=26,M=N*2; 8 char s[N]; 9 int n,k,m,op,ans; 10 11 struct SAM{ 12 int tr[M][tyn],f[M],ml[M],ed,last,p,x,r,q; 13 int cnt[M],b[M],d[M]; 14 inline int gid(char x){return x-'a';} 15 inline void nc(int s,int &p){ 16 ml[p=++ed]=s,f[ed]=cnt[ed]=0,mst(tr[ed],0); 17 } 18 void clear(){ed=0,nc(0,last);} 19 void add(int w,int R=0){ 20 nc(ml[x=last]+1,p),last=R=p; 21 while(x&&!tr[x][w])tr[x][w]=p,x=f[x]; 22 if(!x)f[p]=1; 23 else if(ml[x]+1==ml[q=tr[x][w]])f[p]=q; 24 else{ 25 nc(ml[x]+1,r),f[r]=f[q],f[p]=f[q]=r; 26 memcpy(tr[r],tr[q],sizeof(tr[r])); 27 cnt[r]=cnt[q]; 28 while(x&&tr[x][w]==q)tr[x][w]=r,x=f[x]; 29 } 30 for(;R!=1&&cnt[R]<k;R=f[R]) 31 if(++cnt[R]==k) 32 { 33 ans+=ml[R]-ml[f[R]]; 34 break; 35 } 36 } 37 void build(char *s){for(int i=1;s[i];i++)add(gid(s[i]));} 38 }sam; 39 40 int main() 41 { 42 while(~scanf("%d%d%d",&n,&m,&k)) 43 { 44 scanf("%s",s+1); 45 ans=0,sam.clear(),sam.build(s); 46 F(i,1,m) 47 { 48 scanf("%d",&op); 49 if(op==1) 50 { 51 char now[2]; 52 scanf("%s",now); 53 sam.add(sam.gid(*now)); 54 }else printf("%d\n",ans); 55 } 56 } 57 return 0; 58 }