|
7 | 7 | //! vi s_vec; |
8 | 8 | //! auto [sa1, sa_inv1, lcp1] = sa_short(s_vec); |
9 | 9 | //! @endcode |
10 | | -//! runs in ~1.5s for 5e5 |
| 10 | +//! runs in ~0.5s for 5e5 |
11 | 11 | //! @time O(n * log^2(n)) |
12 | 12 | //! @space O(n) |
13 | 13 | auto sa_short(const auto& s) { |
14 | | - int n = sz(s); |
| 14 | + const int n = sz(s), b = 6; |
15 | 15 | vi sa(n), sa_inv(all(s)), lcp(n - 1); |
16 | 16 | iota(all(sa), 0); |
17 | | - for (int k = 1; k <= n; k *= 2) { |
| 17 | + for (int j = 1; j <= n; j *= b) { |
18 | 18 | vi x(sa_inv); |
19 | | - auto proj = [&](int i) { |
20 | | - return pair(x[i], i + k < n ? x[i + k] : -1); |
| 19 | + auto cmp = [&](int i1, int i2) { |
| 20 | + rep(k, 0, b) { |
| 21 | + int a = i1 + j * k < n ? x[i1 + j * k] : -1; |
| 22 | + int b = i2 + j * k < n ? x[i2 + j * k] : -1; |
| 23 | + if (a != b) return a < b; |
| 24 | + } |
| 25 | + return false; |
21 | 26 | }; |
22 | | - ranges::sort(sa, {}, proj); |
| 27 | + sort(all(sa), cmp); |
23 | 28 | sa_inv[sa[0]] = 0; |
24 | 29 | rep(i, 1, n) sa_inv[sa[i]] = |
25 | | - sa_inv[sa[i - 1]] + (proj(sa[i - 1]) != proj(sa[i])); |
| 30 | + sa_inv[sa[i - 1]] + cmp(sa[i - 1], sa[i]); |
26 | 31 | } |
27 | | - int sz = 0; |
| 32 | + int l = 0; |
28 | 33 | rep(i, 0, n) { |
29 | | - if (sz > 0) sz--; |
| 34 | + if (l > 0) l--; |
30 | 35 | if (sa_inv[i] == 0) continue; |
31 | | - for (int j = sa[sa_inv[i] - 1]; |
32 | | - max(i, j) + sz < n && s[i + sz] == s[j + sz];) |
33 | | - sz++; |
34 | | - lcp[sa_inv[i] - 1] = sz; |
| 36 | + int j = sa[sa_inv[i] - 1]; |
| 37 | + while (max(i, j) + l < n && s[i + l] == s[j + l]) l++; |
| 38 | + lcp[sa_inv[i] - 1] = l; |
35 | 39 | } |
36 | 40 | return tuple{sa, sa_inv, lcp}; |
37 | 41 | } |
0 commit comments