P3809 【模板】后缀排序
后缀数组sa[i]就表示排名为i的后缀的起始位置
x[i]是第i个元素的第一关键字
y[i]表示第二关键字排名为i的数,在第一关键字中的位置
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define N 1000005 #define rint register int int n,m,c[N],sa[N],x[N],y[N]; char s[N]; void get_sa(){ for(rint i=1;i<=n;++i) ++c[x[i]=s[i]]; for(rint i=1;i<=m;++i) c[i]+=c[i-1]; for(rint i=n;i>=1;--i) sa[c[x[i]]--]=i; for(rint k=1;k<=n;k<<=1){ rint u=0; for(rint i=n-k+1;i<=n;++i) y[++u]=i;//逆序也没关系,因为都是没有 for(rint i=1;i<=n;++i) if(sa[i]>k) y[++u]=sa[i]-k; for(rint i=1;i<=m;++i) c[i]=0; for(rint i=1;i<=n;++i) ++c[x[i]]; for(rint i=1;i<=m;++i) c[i]+=c[i-1]; for(rint i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;//按第二关键字排序 swap(x,y); x[sa[1]]=1; u=1; for(rint i=2;i<=n;++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?u:++u; if(u==n){break;} m=u; } } int main(){ scanf("%s",s+1); n=strlen(s+1),m=125; get_sa(); for(rint i=1;i<=n;++i) printf("%d ",sa[i]); return 0; }
sa求最长公共前缀
void get_height() //求最长公共前缀 { for(rint i=1;i<=n;i++) rk[sa[i]]=i; rint k=0; for(rint i=1;i<=n;i++) { if(rk[i]==1) continue; if(k) --k; rint j=sa[rk[i]-1]; while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) ++k; height[rk[i]]=k; } }