namespace SA { int n, m, sa[maxn], h[maxn], c[maxn], x[maxn], y[maxn]; voidrsort(){ for (int i = 1; i <= m; i++) c[i] = 0; for (int i = 1; i <= n; i++) c[x[i]]++; for (int i = 1; i <= m; i++) c[i] += c[i - 1]; for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i]; } intcmp(int i, int j, int k){ int a = i + k > n ? -1 : y[i + k]; int b = j + k > n ? -1 : y[j + k]; return y[i] == y[j] && a == b; } voidbuild(int nn, char* s){ n = nn; m = 255; // important for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i; rsort(); for (int k = 1, p; k <= n; k += k, m = p) { p = 0; for (int i = n; i > n - k; i--) y[++p] = i; for (int i = 1; i <= n; i++) if (sa[i] > k) y[++p] = sa[i] - k; rsort(); for (int i = 1; i <= n; i++) swap(x[i], y[i]); x[sa[1]] = p = 1; for (int i = 2; i <= n; i++) x[sa[i]] = cmp(sa[i], sa[i - 1], k) ? p : ++p; } for (int i = 1; i <= n; i++) x[sa[i]] = i; for (int i = 1, k = 0; i <= n; i++) { if (k) k--; int j = sa[x[i] - 1]; while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++; h[x[i]] = k; } } }
namespace SA { int n, m, sa[maxn], h[maxn], c[maxn], x[maxn], y[maxn]; voidrsort(){ for (int i = 1; i <= m; i++) c[i] = 0; for (int i = 1; i <= n; i++) c[x[i]]++; for (int i = 1; i <= m; i++) c[i] += c[i - 1]; for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i]; } intcmp(int i, int j, int k){ int a = i + k > n ? -1 : y[i + k]; int b = j + k > n ? -1 : y[j + k]; return y[i] == y[j] && a == b; } int dp[maxn][21]; voidbuild(int nn, char* s){ n = nn; m = 255; for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i; rsort(); for (int k = 1, p; k <= n; k += k, m = p) { p = 0; for (int i = n; i > n - k; i--) y[++p] = i; for (int i = 1; i <= n; i++) if (sa[i] > k) y[++p] = sa[i] - k; rsort(); for (int i = 1; i <= n; i++) swap(x[i], y[i]); x[sa[1]] = p = 1; for (int i = 2; i <= n; i++) x[sa[i]] = cmp(sa[i], sa[i - 1], k) ? p : ++p; } for (int i = 1; i <= n; i++) x[sa[i]] = i; for (int i = 1, k = 0; i <= n; i++) { if (k) k--; int j = sa[x[i] - 1]; while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++; h[x[i]] = k; } for (int i = 1; i <= n; i++) dp[i][0] = h[i]; for (int j = 1; j < 21; j++) { for (int i = 1; i + (1 << j) <= n + 1; i++) { dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } } intqlcp(int l, int r){ if (l == r) return n - l + 1; l = x[l]; r = x[r]; if (l > r) swap(l, r); l++; int k = 0; while ((1 << (k + 1)) <= r - l + 1) k++; returnmin(dp[l][k], dp[r - (1 << k) + 1][k]); } }
注意
下标从 $1$ 开始。
每个字符的值域范围。
定义
$sa[n]$ : 后缀排序后,排名第 $i$ 个串的开始下标。
$rk[n]$ : 原串第 $i$ 个后缀排过序后的名次。
$sa[n]$ 和 $rk[n]$ 互为逆运算,$rk[sa[i]]=sa[rk[i]]=i$。
$LCP$ : 最长公共前缀。
$height[rk[i]] \ge height[rk[i-1]] - 1$。
$height[i]$ = $LCP(sa[i - 1],sa[i])$ ($2 \le i \le n$)。