#include<bits/stdc++.h>
#define M 1000009
using namespace std;
int n,m,rk[M],tp[M],sa[M],tax[M],height[M];
char s[M];
void Qsort(){
for(int i=0;i<=m;i++) tax[i]=0;//清空桶
for(int i=1;i<=n;i++) tax[rk[i]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];//维护前缀和
for(int i=n;i>=1;i--) sa[tax[rk[tp[i]]]--]=tp[i];//倒着枚举第二关键字
}
void Debug() {
printf("*****************\n");
printf("下标"); for (int i = 1; i <= n; i++) printf("%d ", i); printf("\n");
printf("sa "); for (int i = 1; i <= n; i++) printf("%d ", sa[i]); printf("\n");
printf("rk "); for (int i = 1; i <= n; i++) printf("%d ", rk[i]); printf("\n");
printf("tp "); for (int i = 1; i <= n; i++) printf("%d ", tp[i]); printf("\n");
}
void getheight(){
int k=0;
for(int i=1;i<=n;i++){
if(k) k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[k+j]) k++;
height[rk[i]]=k;
}
}
void Suffix(){
for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
m=127,Qsort();//m表示字符集大小
for(int w=1,p=0;p<n;m=p,w<<=1){
//w表示当前倍增的长度,现在已知长度为w的sa,要求长度为2w的
//p表示不同的排名个数(因为rank有重复) ,p=n时则排序完成
//Debug();
p=0;//此处p仅用于计数(节约变量)
for(int i=1;i<=w;i++) tp[++p]=n-w+i;//有w个数的第二关键字都会是0,因此排名靠前
for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;//处理第二关键字
Qsort();//排序
std::swap(tp,rk);//将上一轮rk值赋给tp,因为tp已经没用了
rk[sa[1]]=p=1;
for(int i=2;i<=n;i++)
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;//当两个关键字排名都相同时,排名相同
}for(int i=1;i<=n;i++) printf("%d ",sa[i]);
printf("\n");
//getheight();
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
Suffix();
return 0;
}
推荐后缀数组学习博客:https://www.cnblogs.com/zwfymqz/p/8413523.html
%%%%%%