后缀是从字符串的某个位置到字符串末尾的非空子串。例如:$suff(HORSE) = \{E, SE, RSE, ORSE, HORSE\}$。
后缀数组是包含字符串所有已排序后缀的数组。例如:$sa(CAMEL) = \{1-AMEL, 0-CAMEL, 3-EL, 4-L, 2-MEL\} = \{1, 0, 3, 4, 2\}$。
首先可以想出一种基于快速排序的后缀数组求法,但是时间复杂度为$O(n^2logn)$。可用一种倍增算法来优化,时间复杂度$O(nlogn)$,待补。
后缀数组用于事先不知道模板P的多模板匹配问题,此时需要处理文本串T。
sa是后缀排名到位置的映射
x是第一关键字位置到排名(数值)的映射
y是第二关键字排名到位置的映射
c是基数排序的桶

例题:洛谷P3809
#include<bits/stdc++.h>
using namespace std;
const int N = 1000050;
char s[N], p[N];
int sa[N], x[N], y[N], c[N], n;
void build_sa(int m) {
n = strlen(s + 1);
for(int i = 1; i <= n; i++) c[x[i] = s[i]]++;
for(int i = 2; i <= m; i++) c[i] += c[i-1];
for(int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
for(int k = 1; k <= n; k <<= 1) {
int p = 1;
for(int i = n - k + 1; i <= n; i++) y[p++] = i;
for(int i = 1; i <= n; i++) if(sa[i] > k) y[p++] = sa[i] - k;
for(int i = 1; i <= m; i++) c[i] = 0;
for(int i = 1; i <= n; i++) c[x[i]]++;
for(int i = 2; i <= m; i++) c[i] += c[i-1];
for(int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];
swap(x, y);
p = 1; x[sa[1]] = 1;
for(int i = 2; i <= n; i++)
x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p : ++p;
if(p == n) break;
m = p;
}
}
int main() {
gets(s + 1);
build_sa(200);
for(int i = 1; i <= n; i++) printf("%d ", sa[i]);
}
来源:https://www.cnblogs.com/nioh/p/12298340.html