动态更新后缀自动机,每次不断依据当前添加的节点不断往前寻找父节点上字符串最多可出现的次数
这里为了减少运算,当父节点已经达到k次就不在往前寻找,因为之前的必然达到k次,也已经统计在内
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 #define N 500010 7 #define M 26 8 9 struct SamNode{ 10 SamNode *son[26] , *f; 11 int l , sc; 12 void init(){ 13 f = NULL; 14 for(int i=0 ; i<26 ; i++) son[i] = NULL; 15 l = sc = 0; 16 } 17 }*root , *last , sam[N]; 18 19 int cnt , n , m , k , ret; 20 char s[N]; 21 22 void init(){ 23 sam[0].init(); 24 root = last = &sam[cnt=0]; 25 ret = 0; 26 } 27 28 void add(int x) 29 { 30 SamNode *p = &sam[++cnt] , *jp=last; 31 p->init(); 32 p->l = jp->l+1; 33 last = p; 34 for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x]=p; 35 if(!jp) p->f = root; 36 else{ 37 if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x]; 38 else{ 39 SamNode *r = &sam[++cnt] , *q = jp->son[x]; 40 r->init(); 41 *r = *q; 42 r->l = jp->l+1; 43 q->f = p->f = r; 44 for( ; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r; 45 } 46 } 47 while(p!=root && p->sc<k){ 48 p->sc++; 49 if(p->sc == k) ret+=(p->l-p->f->l); 50 p = p->f; 51 } 52 } 53 54 void solve() 55 { 56 for(int i=0 ; i<n ; i++) add(s[i]-'a'); 57 // for(int i=0 ; i<=5 ; i++) cout<<i<<" :"<<sam[i].sc<<endl; 58 int op; 59 char c[3]; 60 for(int i=0 ; i<m ; i++){ 61 scanf("%d" , &op); 62 if(op == 2) printf("%d " , ret); 63 else{ 64 scanf("%s" , c); 65 add(c[0]-'a'); 66 } 67 //debug 68 // for(int i=0 ; i<=5 ; i++) cout<<i<<" :"<<sam[i].sc<<endl; 69 } 70 } 71 72 int main() 73 { 74 // freopen("a.in" , "r" , stdin); 75 while(~scanf("%d%d%d" , &n , &m , &k)) 76 { 77 scanf("%s" , s); 78 init(); 79 solve(); 80 } 81 return 0; 82 }