#include<stdio.h> #include<cstring> #include<algorithm> #include<iostream> #include<cstring> using namespace std; const int maxn = 1e6+7; char str[maxn]; int sa[maxn],tp[maxn],rak[maxn],tax[maxn],a[maxn],M,N; // sa代表着 排名第i小的下标是什么 // rak 代表 下标为i的串的排名是什么 // 顾 rak[sa[i]]==i sa[rak[i]]=i void qsort(){ for(int i=0;i<=M;i++) tax[i]=0; for(int i=1;i<=N;i++) tax[rak[i]]++; for(int i=1;i<=M;i++) tax[i]+=tax[i-1]; // 这个循环操作相当于把 在原来sa的基础上 再次按照 tp的rank排名 再排序 for(int i=N;i>=1;i--) sa[ tax[rak[tp[i]]]-- ]=tp[i]; } void Ssort(){ M=127; for(int i=1;i<=N;i++)rak[i]=a[i],tp[i]=i; qsort(); for(int w=1,p=1; p<N ; M=p,w<<=1) { p=0; //更新第二关键值 /**********************************/ for(int i=N-w+1;i<=N;i++) tp[++p]=i;// 长度越界,第二关键字为0 for(int i=1;i<=N;i++) if(sa[i]>w) tp[++p]=sa[i]-w; /**********************************/ qsort(); // 把 rak里面的数据转移到tp里面 swap(rak,tp); //这个操作等于统计了下次需要的桶的个数 rak[sa[1]]=p=1; for(int i=2;i<=N;i++) rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p; } } int height[maxn]; //height[i]为LCP(i,i-1) //LCP(i,j)为suff(sa[i])与suff(sa[j])的最长公共前缀 /* LCP的性质 LCP(i,j)=LCP(j,i); LCP(i,i)=len(sa[i])=n-sa[i]+1; */ //LCP(rk[i],rk[k+1])=height[rk[i-1]]-1; int get_height() { int k=0; for (int i=1;i<=N;++i) rak[sa[i]]=i; for (int i=1;i<=N;++i) { if (rak[i]==1) continue;//第一名height为0 if (k) --k;//h[i]>=h[i-1]+1; int j=sa[rak[i]-1]; while (j+k<=N && i+k<=N && a[i+k]==a[j+k]) ++k; height[rak[i]]=k;//h[i]=height[rk[i]]; } for (int i=1;i<=N;++i)cout<<height[i]<<endl; } int main() { scanf("%s",str); N=strlen(str); for(int i=1;i<=N;i++)a[i]=str[i-1]-48; Ssort(); for(int i=1;i<=N;i++) printf("%d ",sa[i]); puts(""); get_height(); return 0; } ababa 5 3 1 4 2 0 1 3 0 2
#include<stdio.h> #include<cstring> #include<algorithm> #include<iostream> #include<cstring> using namespace std; const int maxn = 1e6+7; char str[maxn]; int sa[maxn],tp[maxn],rak[maxn],tax[maxn],a[maxn],M,N; // sa代表着 排名第i小的下标是什么 // rak 代表 下标为i的串的排名是什么 // 顾 rak[sa[i]]==i sa[rak[i]]=i void qsort(){ for(int i=0;i<=M;i++) tax[i]=0; for(int i=1;i<=N;i++) tax[rak[i]]++; for(int i=1;i<=M;i++) tax[i]+=tax[i-1]; // 这个循环操作相当于把 在原来sa的基础上 再次按照 tp的rank排名 再排序 for(int i=N;i>=1;i--) sa[ tax[rak[tp[i]]]-- ]=tp[i]; } void Ssort(){ M=127; for(int i=1;i<=N;i++)rak[i]=a[i],tp[i]=i; qsort(); for(int w=1,p=1; p<N ; M=p,w<<=1) { p=0; //更新第二关键值 /**********************************/ for(int i=N-w+1;i<=N;i++) tp[++p]=i;// 长度越界,第二关键字为0 for(int i=1;i<=N;i++) if(sa[i]>w) tp[++p]=sa[i]-w; /**********************************/ qsort(); // 把 rak里面的数据转移到tp里面 swap(rak,tp); //这个操作等于统计了下次需要的桶的个数 rak[sa[1]]=p=1; for(int i=2;i<=N;i++) rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p; } } int height[maxn]; //height[i]为LCP(i,i-1) //LCP(i,j)为suff(sa[i])与suff(sa[j])的最长公共前缀 /* LCP的性质 LCP(i,j)=LCP(j,i); LCP(i,i)=len(sa[i])=n-sa[i]+1; */ //LCP(rk[i],rk[k+1])=height[rk[i-1]]-1; int get_height() { int k=0; for (int i=1;i<=N;++i) rak[sa[i]]=i; for (int i=1;i<=N;++i) { if (rak[i]==1) continue;//第一名height为0 if (k) --k;//h[i]>=h[i-1]+1; int j=sa[rak[i]-1]; while (j+k<=N && i+k<=N && a[i+k]==a[j+k]) ++k; height[rak[i]]=k;//h[i]=height[rk[i]]; } for (int i=1;i<=N;++i)cout<<height[i]<<endl; } int main() { scanf("%s",str); N=strlen(str); for(int i=1;i<=N;i++)a[i]=str[i-1]-48; Ssort(); for(int i=1;i<=N;i++) printf("%d ",sa[i]); puts(""); get_height(); return 0; } ababa 5 3 1 4 2 0 1 3 0 2