upd 2019/05/14 :给代码加上了注释
题目:后缀排序
大佬的讲解:后缀数组详解 [自为风月马前卒]
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000
int n;
char a[maxn+5];
int m; //桶的个数
int sa[maxn+5],rk[maxn+5]; //排名为sa[i]的子串为[sa[i],n],子串[i,n]的排名为rk[i]
int tax[maxn+5],tp[maxn+5]; //基数排序相关
//tax:桶中的元素个数
void readin() {
scanf("%s",a+1);
n=strlen(a+1);
}
void rsort() {
memset(tax,0,sizeof(tax));
for(int i=1;i<=n;i++) tax[rk[tp[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]; //倒着从桶中取出,计算sa
}
void makesa() {
for(int i=1;i<=n;i++) rk[i]=(int)a[i],tp[i]=i; //初始化排名
rsort();
for(int k=1;k<=n;k<<=1) { //排序长度小于等于2^k的后缀
int num=0;
//rk[i]:第一关键字,即当前子串的排名
//tp[num]:第二关键字排名为num的字符串编号
for(int i=n-k+1;i<=n;i++) tp[++num]=i; //没有第二关键字的
for(int i=1;i<=n;i++) if(sa[i]>k) tp[++num]=sa[i]-k; //sa[i]为sa[i]-k的第二关键字
rsort();
swap(rk,tp); //tp变为上一次的rk
rk[sa[1]]=1;
num=1; //下一次需要桶的个数
for(int i=2;i<=n;i++) {
if(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k]) rk[sa[i]]=num; //排名相同
else rk[sa[i]]=++num; //排名不同
}
if(num==n) break; //倍增结束
m=num;
}
}
int main() {
readin();
m=122;
makesa();
for(int i=1;i<=n;i++) printf("%d ",sa[i]);
return 0;
}