F10【模板】后缀数组(SA)
视频链接:610 后缀数组(SA)_哔哩哔哩_bilibili
// Luogu P3809 【模板】后缀排序 #include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N=2000010; char s[N]; int n,m;//n为后缀个数, m为桶的个数 int x[N],y[N],c[N],sa[N],rk[N],height[N]; //桶数组x[i],辅助数组y[i],计数数组c[i] void get_sa(){ int i,j,k; //按第一个字母排序 for(i=1;i<=n;i++)c[x[i]=s[i]]++; for(i=1;i<=m;i++)c[i]+=c[i-1]; for(i=n;i;i--)sa[c[x[i]]--]=i; for(k=1;k<=n;k<<=1){ //logn轮 //按第二关键字排序 memset(c,0,sizeof(c)); for(i=1;i<=n;i++)y[i]=sa[i]; for(i=1;i<=n;i++)c[x[y[i]+k]]++; for(i=1;i<=m;i++)c[i]+=c[i-1]; for(i=n;i;i--)sa[c[x[y[i]+k]]--]=y[i]; //按第一关键字排序 memset(c,0,sizeof(c)); for(i=1;i<=n;i++)y[i]=sa[i]; for(i=1;i<=n;i++)c[x[y[i]]]++; for(i=1;i<=m;i++)c[i]+=c[i-1]; for(i=n;i;i--)sa[c[x[y[i]]]--]=y[i]; //把后缀放入桶数组 for(i=1;i<=n;i++)y[i]=x[i]; for(m=0,i=1;i<=n;i++) if(y[sa[i]]==y[sa[i-1]]&& y[sa[i]+k]==y[sa[i-1]+k])x[sa[i]]=m; else x[sa[i]]=++m; if(m==n)break;//已排好 } } void get_height(){ int i,j,k; for(i=1;i<=n;i++)rk[sa[i]]=i; for(i=1,k=0;i<=n;i++){ //枚举后缀i if(rk[i]==1)continue;//第一名height为0 if(k)k--;//上一个后缀的height值减1 int j=sa[rk[i]-1];//找出后缀i的前邻后缀j while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++; height[rk[i]]=k; } } int main(){ scanf("%s",s+1); n=strlen(s+1); m=122; get_sa(); get_height(); for(int i=1;i<=n;i++)printf("%d ",sa[i]); // puts(""); // for(int i=1;i<=n;i++)printf("%d ",height[i]); return 0; }