LG P3809 【模板】字尾排序
阿新 • • 發佈:2021-08-13
貼模板
注意:\(\text{id}\) 表示第二關鍵字排序後(其實無需排序,利用上輪的 \(\text{sa}\) 值即可)相應的第一關鍵字的位置
計數排序為了穩定性最後確定位置時要倒著開始
複製的 \(\text{ork}\) 要開兩倍
\(\text{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]); }