后缀自动机学习笔记

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 }

 

posted @ 2018-06-25 09:49  DCDCBigBig  阅读(123)  评论(0编辑  收藏  举报