贴模板
注意:( ext{id}) 表示第二关键字排序后(其实无需排序,利用上轮的 ( ext{sa}) 值即可)相应的第一关键字的位置
计数排序为了稳定性最后确定位置时要倒着开始
复制的 ( ext{ork}) 要开两倍
( ext{Code})
#include <cstdio>
#include <cstring>
#define re register
using namespace std;
const int N = 1e6 + 5;
int n, sa[N], rk[N], cnt[N], id[N], ork[N << 1];
char s[N];
inline int comp(int x, int y, int w){return (ork[x] == ork[y]) && (ork[x + w] == ork[y + w]);}
inline void build_SA()
{
int m = 300, p;
for(re int i = 1; i <= n; i++) ++cnt[rk[i] = s[i]];
for(re int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(re int i = n; i; i--) sa[cnt[rk[i]]--] = i;
for(re int w = 1; w < n; w <<= 1, m = p)
{
p = 0;
for(re int i = n - w + 1; i <= n; i++) id[++p] = i;
for(re int i = 1; i <= n; i++)
if (sa[i] > w) id[++p] = sa[i] - w;
for(re int i = 0; i <= m; i++) cnt[i] = 0;
for(re int i = 1; i <= n; i++) ++cnt[rk[id[i]]];
for(re int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(re int i = n; i; i--) sa[cnt[rk[id[i]]]--] = id[i];
for(re int i = 1; i <= n; i++) ork[i] = rk[i];
p = 0;
for(re int i = 1; i <= n; i++)
rk[sa[i]] = comp(sa[i], sa[i - 1], w) ? p : ++p;
if (p >= n) break;
}
}
int main()
{
scanf("%s", s + 1), n = strlen(s + 1), build_SA();
for(re int i = 1; i <= n; i++) printf("%d ", sa[i]);
}