Skip to content

Commit bb6571f

Browse files
lrvideckisweb-flow
andauthored
sa short nits (#176)
* Modify suffix array algorithm to use K-based sorting Refactor suffix array construction to use a base K for sorting. * [auto-verifier] verify commit 2ddf97e * Update suffix array test to include LCP verification * [auto-verifier] verify commit 711cb9b * Fix loop range in suffix array test * Fix condition in suffix array test case * [auto-verifier] verify commit 2cb9676 * Update suffix_array_short.hpp * Fix suffix array index handling in LCP calculation * Fix LCP calculation in suffix array implementation * Fix lcp calculation in suffix_array_short.hpp * Update LCP calculation to use min function * Refactor suffix array sorting and LCP computation * Improve suffix array comparison handling Refactor comparison logic to handle -1 case in suffix array. * Add assertion for index 'a' in suffix array Add assertion to ensure 'a' is within bounds before accessing 'y'. * Refactor conditionals for clarity in suffix_array_short.hpp * Update suffix_array_short.hpp * fix * [auto-verifier] verify commit 8fd2384 * fix * nameing nit * fixes * copy change here too * fix --------- Co-authored-by: GitHub <noreply@github.com>
1 parent 97d50cf commit bb6571f

File tree

6 files changed

+36
-27
lines changed

6 files changed

+36
-27
lines changed

.verify-helper/timestamps.remote.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@
106106
"tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2026-01-18 11:15:41 +0000",
107107
"tests/library_checker_aizu_tests/monotonic_stack_related/max_rect_histogram.test.cpp": "2026-01-18 11:15:41 +0000",
108108
"tests/library_checker_aizu_tests/strings/kmp.test.cpp": "2025-08-05 19:19:23 -0600",
109-
"tests/library_checker_aizu_tests/strings/lcp_array.test.cpp": "2025-08-05 19:19:23 -0600",
110109
"tests/library_checker_aizu_tests/strings/lcp_query_palindrome.test.cpp": "2026-01-18 11:15:41 +0000",
111110
"tests/library_checker_aizu_tests/strings/lcp_query_zfunc.test.cpp": "2026-01-18 11:15:41 +0000",
112111
"tests/library_checker_aizu_tests/strings/lcs_dp.test.cpp": "2025-08-05 19:19:23 -0600",
@@ -119,7 +118,6 @@
119118
"tests/library_checker_aizu_tests/strings/sa_sort_pairs.test.cpp": "2026-01-18 11:15:41 +0000",
120119
"tests/library_checker_aizu_tests/strings/single_matching_bs.test.cpp": "2026-01-18 11:15:41 +0000",
121120
"tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2026-01-18 11:15:41 +0000",
122-
"tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2025-08-05 19:19:23 -0600",
123121
"tests/library_checker_aizu_tests/strings/trie.test.cpp": "2026-01-17 12:38:18 -0700",
124122
"tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2025-08-05 19:19:23 -0600",
125123
"tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2025-12-11 21:47:53 +0000",

library/strings/suffix_array/suffix_array.hpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,13 @@ auto get_sa(const auto& s, int max_num) {
5757
}
5858
if (max_num == n) break;
5959
}
60-
int sz = 0;
60+
int l = 0;
6161
rep(i, 0, n) {
62-
if (sz > 0) sz--;
62+
if (l > 0) l--;
6363
if (sa_inv[i] == 0) continue;
64-
for (int j = sa[sa_inv[i] - 1];
65-
max(i, j) + sz < n && s[i + sz] == s[j + sz];)
66-
sz++;
67-
lcp[sa_inv[i] - 1] = sz;
64+
int j = sa[sa_inv[i] - 1];
65+
while (max(i, j) + l < n && s[i + l] == s[j + l]) l++;
66+
lcp[sa_inv[i] - 1] = l;
6867
}
6968
return tuple{sa, sa_inv, lcp};
7069
}

library/strings/suffix_array/suffix_array_short.hpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,35 @@
77
//! vi s_vec;
88
//! auto [sa1, sa_inv1, lcp1] = sa_short(s_vec);
99
//! @endcode
10-
//! runs in ~1.5s for 5e5
10+
//! runs in ~0.5s for 5e5
1111
//! @time O(n * log^2(n))
1212
//! @space O(n)
1313
auto sa_short(const auto& s) {
14-
int n = sz(s);
14+
const int n = sz(s), b = 6;
1515
vi sa(n), sa_inv(all(s)), lcp(n - 1);
1616
iota(all(sa), 0);
17-
for (int k = 1; k <= n; k *= 2) {
17+
for (int j = 1; j <= n; j *= b) {
1818
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;
2126
};
22-
ranges::sort(sa, {}, proj);
27+
sort(all(sa), cmp);
2328
sa_inv[sa[0]] = 0;
2429
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]);
2631
}
27-
int sz = 0;
32+
int l = 0;
2833
rep(i, 0, n) {
29-
if (sz > 0) sz--;
34+
if (l > 0) l--;
3035
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;
3539
}
3640
return tuple{sa, sa_inv, lcp};
3741
}

tests/.config/.cppcheck_suppression_list

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ syntaxError:../library/loops/supermasks.hpp:8
4040
syntaxError:../library/math/prime_sieve/mobius.hpp:6
4141
syntaxError:../library/trees/lca_rmq/iterate_subtree.hpp:6
4242
knownConditionTrueFalse:../library/strings/suffix_array/suffix_array.hpp:62
43-
knownConditionTrueFalse:../library/strings/suffix_array/suffix_array_short.hpp:29
43+
knownConditionTrueFalse:../library/strings/suffix_array/suffix_array_short.hpp:34
4444
knownConditionTrueFalse:../library/dsu/kruskal_tree.hpp:15
4545
knownConditionTrueFalse:../library/dsu/dsu.hpp:11
4646
constVariable:../kactl/content/numerical/NumberTheoreticTransform.h:30

tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,22 @@ int main() {
99
cin.tie(0)->sync_with_stdio(0);
1010
string s;
1111
cin >> s;
12-
auto [sa, sa_inv, _] = sa_short(vi(all(s)));
13-
for (int i = 0; i < sz(s); i++) {
12+
auto [sa, sa_inv, lcp] = sa_short(vi(all(s)));
13+
rep(i, 0, sz(s)) {
1414
assert(sa[sa_inv[i]] == i);
1515
assert(sa_inv[sa[i]] == i);
1616
}
17+
vi lcp_kasai(sz(s) - 1);
18+
int sz = 0;
19+
rep(i, 0, sz(s)) {
20+
if (sz > 0) sz--;
21+
if (sa_inv[i] == 0) continue;
22+
for (int j = sa[sa_inv[i] - 1];
23+
max(i, j) + sz < sz(s) && s[i + sz] == s[j + sz];)
24+
sz++;
25+
lcp_kasai[sa_inv[i] - 1] = sz;
26+
}
27+
assert(lcp == lcp_kasai);
1728
for (int val : sa) cout << val << " ";
1829
cout << '\n';
1930
}

tests/scripts/grep_clangformat_cppcheck.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ grep --extended-regexp "template\s?<typename" --recursive ../library/ && exit 1
1616
echo "check 1 instead of true"
1717
grep "true" --recursive ../library/ && exit 1
1818

19-
echo "check 0 instead of false"
20-
grep "false" --recursive ../library/ && exit 1
21-
2219
echo "check ll instead of long long or int64_t"
2320
grep "long long" --recursive ../library/ && exit 1
2421
grep "int64_t" --recursive ../library/**/*.hpp | grep "uint64_t" --invert-match && exit 1

0 commit comments

Comments
 (0)