后缀自动机学习笔记
Orz CLJ!!!
后缀自动机
1 //SPOJ8222
2 //题目大意:
3 //给长度为 n 的字符串 S , 对任意的 L , 求长度为 L 的子串最多出现的次数
4 #include<iostream>
5 #include<cstring>
6 #include<cstdio>
7 #include<cmath>
8 #include<queue>
9 using namespace std;
10 int len,ans[500010];
11 char s[300001];
12 struct SAM{
13 int now,tot,rt,last,son[500010][26],fa[500010],mx[500010],l1[500010],l2[500010],siz[500010];
14 void init(){
15 memset(son,0,sizeof(son));
16 tot=rt=last=1;
17 mx[1]=0;
18 }
19 void extend(int ch){
20 int p=last,np=++tot;
21 mx[np]=mx[p]+1;
22 for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
23 if(!p)fa[np]=rt;
24 else{
25 int q=son[p][ch];
26 if(mx[q]==mx[p]+1)fa[np]=q;
27 else{
28 int nq=++tot;
29 mx[nq]=mx[p]+1;
30 memcpy(son[nq],son[q],sizeof(son[q]));
31 fa[nq]=fa[q];
32 fa[q]=fa[np]=nq;
33 for(;son[p][ch]==q;p=fa[p])son[p][ch]=nq;
34 }
35 }
36 last=np;
37 siz[np]=1;
38 }
39 void solve(){
40 for(int i=1;i<=tot;i++)l1[mx[i]]++;
41 for(int i=2;i<=len;i++)l1[i]+=l1[i-1];
42 for(int i=1;i<=tot;i++)l2[l1[mx[i]]--]=i;
43 for(int i=tot;i;i--){
44 siz[fa[l2[i]]]+=siz[l2[i]];
45 ans[mx[l2[i]]]=max(ans[mx[l2[i]]],siz[l2[i]]);
46 }
47 }
48 }sam;
49 int main(){
50 memset(ans,0,sizeof(ans));
51 scanf("%s",s);
52 sam.init();
53 len=strlen(s);
54 for(int i=0;i<len;i++){
55 sam.extend(s[i]-'a');
56 }
57 sam.solve();
58 for(int i=1;i<=len;i++){
59 printf("%d\n",ans[i]);
60 }
61 return 0;
62 }