|
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 | | - const int n = sz(s), K = 4; |
| 14 | + const int n = sz(s), K = 6; |
15 | 15 | vi sa(n), sa_inv(all(s)), lcp(n - 1); |
16 | 16 | iota(all(sa), 0); |
17 | 17 | for (int j = 1; j <= n; j *= K) { |
18 | | - vi x(sa_inv), y(n, -1); |
19 | | - rep (i, 0, n - 1) y[sa[i]] = lcp[i]; |
20 | | - int val; |
| 18 | + vi x(sa_inv); |
21 | 19 | auto cmp = [&](int i1, int i2) { |
22 | | - val = 0; |
23 | 20 | rep (k, 0, K) { |
24 | 21 | int a = i1 + j * k < n ? x[i1 + j * k] : -1; |
25 | 22 | int b = i2 + j * k < n ? x[i2 + j * k] : -1; |
26 | | - if (a != b) { |
27 | | - if (a != -1) val += y[i1 + j * k]; |
28 | | - return a < b; |
29 | | - } |
30 | | - val += j; |
| 23 | + if (a != b) return a < b; |
31 | 24 | } |
32 | 25 | return false; |
33 | 26 | }; |
34 | | - ranges::sort(sa, cmp); |
| 27 | + sort(all(sa), cmp); |
35 | 28 | sa_inv[sa[0]] = 0; |
36 | | - rep(i, 0, n - 1) { |
37 | | - sa_inv[sa[i + 1]] = sa_inv[sa[i]] + cmp(sa[i], sa[i + 1]); |
38 | | - lcp[i] = val; |
39 | | - } |
| 29 | + rep(i, 1, n) |
| 30 | + sa_inv[sa[i]] = sa_inv[sa[i - 1]] + cmp(sa[i - 1], sa[i]); |
| 31 | + } |
| 32 | + int sz = 0; |
| 33 | + rep(i, 0, n) { |
| 34 | + if (sz > 0) sz--; |
| 35 | + if (sa_inv[i] == 0) continue; |
| 36 | + int j = sa[sa_inv[i] - 1]; |
| 37 | + while(max(i, j) + sz < n && s[i + sz] == s[j + sz];) sz++; |
| 38 | + lcp[sa_inv[i] - 1] = sz; |
40 | 39 | } |
41 | 40 | return tuple{sa, sa_inv, lcp}; |
42 | 41 | } |
0 commit comments