- 前言
- 代码
- 1.SA
- 2.SAM
前言
SA 后缀数组模板
SAM 后缀自动机模板
#include2.SAM#include using namespace std; const int maxn = 1e6 + 6; char s[maxn]; int rk[maxn], sa[maxn], height[maxn]; int sa2[maxn], oldrk[maxn], tank[maxn]; int n, m; bool cmp(int x, int y, int w) { return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w]; } void rsort() { // sa2为基数排序而构造 for (int i = 1; i <= m; i++) tank[i] = 0; for (int i = 1; i <= n; i++) tank[rk[sa2[i]]]++; for (int i = 2; i <= m; i++) tank[i] += tank[i - 1]; for (int i = n; i >= 1; i--) sa[tank[rk[sa2[i]]]--] = sa2[i]; } void getSA() { for (int i = 1; i <= n; i++) rk[i] = s[i], sa2[i] = i; rsort(); // 对SA进行基数排序 for (int k = 1; k <= n; k <<= 1) { int cnt = 0; // 对第二关键字的SA2进行排序(非计数排序) for (int i = n - k + 1; i <= n; i++) sa2[++cnt] = i; for (int i = 1; i <= n; i++) if (sa[i] > k) sa2[++cnt] = sa[i] - k; rsort(); // 对SA进行基数排序(与rk本质同,只是排序的方式不同) swap(rk, oldrk); cnt = 1; // 对rk进行倍增比较排序 rk[sa[1]] = 1; for (int i = 2; i <= n; i++) { if (cmp(sa[i], sa[i - 1], k)) rk[sa[i]] = cnt; else rk[sa[i]] = ++cnt; } m = cnt; } } void getHI() { int k = 0; for (int i = 1; i <= n; i++) { if (rk[i] == 1) continue; int j = sa[rk[i] - 1]; if (k) k--; while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++; height[rk[i]] = k; } } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); scanf("%s", s + 1); n = strlen(s + 1); m = 127; getSA(); getHI(); printf("rk: "); for (int i = 1; i <= n; i++) printf("%d ", rk[i]); printf("n"); printf("sa: "); for (int i = 1; i <= n; i++) printf("%d ", sa[i]); printf("n"); return 0; }
#include#include #include



