m = 256; // m refers to the maximum of the value of rk
for (int i=1; i <= n; i++) b[rk[i] = s[i]]++; // b is a bucket
for (int i=1; i <= m; i++) b[i] += b[i-1];
for (int i=n; i >= 1; i--) sa[b[rk[i]]--] = i;
for (int w=1; w <= n; w <<= 1)
{
// The first key word is rk[i] while the second is rk[i+w]
// The second key word doesn't need counting sort
int c0 = 0;
for (int i=n-w+1; i <= n; i++) c[++c0] = i; // [n-w+1,n] don't have the second key word, so they're the smallest
for (int i=1; i <= n; i++) // i refers to the value of the second key word
if (sa[i] > w) c[++c0] = sa[i]-w; // sa[i] is the position of i
// Then we get an array c sorted by the second key word
// Sort the first key word
clear(b);
for (int i=1; i <= n; i++) b[rk[i]]++;
for (int i=1; i <= m; i++) b[i] += b[i-1];
for (int i=n; i >= 1; i--) sa[b[rk[c[i]]]--] = c[i]; // Two-key-word counting sort
memcpy(old,rk,sizeof old); // old rk
// Compute new rk
for (int i=1; i <= n; i++)
{
if (old[sa[i]] == old[sa[i-1]] && old[sa[i]+w] == old[sa[i-1]+w]) rk[sa[i]] = rk[sa[i-1]];
else rk[sa[i]] = rk[sa[i-1]]+1;
}
}
简单应用
例题二:字符加密。
题目大意:求字符串 s 最小的循环同构串。
把原字符串复制一遍,就变成了后缀排序问题。
例题三:【模板】AC自动机。
题目大意:给出文本串 s 和多个模式串 t_i,求 t 在 s 中有没有出现。
因为我找不到别的题了,所以就只能用这一题。
若 t_i 在 s 中有出现,那么它一定是一个后缀的前缀。那么我们在 sa 上二分,找到最小的 \geqslant t_i 的后缀即可。
时间复杂度为 \operatorname O(|t_i|\log n),比 AC 自动机多一个 \log,但是在线。
高度数组 height(以下有时简称为 h)
设 height_i=\text{lcp}(sa_i,sa_{i-1}),即排名第 i 的后缀和排名第 i-1 的后缀的最长公共前缀(的长度) 。