diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index 904dc3cf..b889bacf 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -33,15 +33,15 @@ "tests/library_checker_aizu_tests/data_structures/line_tree_lib_checker.test.cpp": "2025-02-10 23:30:47 -0700", "tests/library_checker_aizu_tests/data_structures/merge_sort_tree.test.cpp": "2025-02-11 13:53:30 -0700", "tests/library_checker_aizu_tests/data_structures/mode_query.test.cpp": "2025-02-10 23:30:47 -0700", -"tests/library_checker_aizu_tests/data_structures/permutation_tree.test.cpp": "2025-06-03 13:37:20 -0600", +"tests/library_checker_aizu_tests/data_structures/permutation_tree.test.cpp": "2025-08-03 18:39:58 -0600", "tests/library_checker_aizu_tests/data_structures/persistent_queue_tree.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/data_structures/persistent_seg_tree.test.cpp": "2024-12-05 10:41:42 -0600", "tests/library_checker_aizu_tests/data_structures/pq_ds_undo_sliding_window.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/data_structures/pq_ds_undo_with_dsu.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp": "2025-02-10 23:30:47 -0700", "tests/library_checker_aizu_tests/data_structures/rmq_disjoint_sparse_table.test.cpp": "2024-12-15 14:34:10 -0600", -"tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp": "2025-06-03 13:37:20 -0600", -"tests/library_checker_aizu_tests/data_structures/rmq_sparse_table.test.cpp": "2025-06-03 13:37:20 -0600", +"tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp": "2025-08-03 18:39:58 -0600", +"tests/library_checker_aizu_tests/data_structures/rmq_sparse_table.test.cpp": "2025-08-03 18:39:58 -0600", "tests/library_checker_aizu_tests/data_structures/rmq_sparse_table_inc.test.cpp": "2024-12-15 14:34:10 -0600", "tests/library_checker_aizu_tests/data_structures/simple_tree.test.cpp": "2024-12-14 15:47:13 -0600", "tests/library_checker_aizu_tests/data_structures/simple_tree_inc.test.cpp": "2024-12-21 00:23:10 -0500", @@ -78,8 +78,8 @@ "tests/library_checker_aizu_tests/handmade_tests/mobius.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/handmade_tests/mod_int.test.cpp": "2024-12-14 19:50:29 -0600", "tests/library_checker_aizu_tests/handmade_tests/n_choose_k.test.cpp": "2025-01-15 00:22:31 -0700", -"tests/library_checker_aizu_tests/handmade_tests/permutation_tree_small.test.cpp": "2025-06-03 13:37:20 -0600", -"tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp": "2025-06-03 13:37:20 -0600", +"tests/library_checker_aizu_tests/handmade_tests/permutation_tree_small.test.cpp": "2025-08-03 18:39:58 -0600", +"tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp": "2025-08-03 18:39:58 -0600", "tests/library_checker_aizu_tests/handmade_tests/sa_find_subarray.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/handmade_tests/seg_tree_find.test.cpp": "2024-12-14 19:50:29 -0600", "tests/library_checker_aizu_tests/handmade_tests/seg_tree_find_small.test.cpp": "2024-12-14 19:50:29 -0600", @@ -107,9 +107,9 @@ "tests/library_checker_aizu_tests/math/xor_basis.test.cpp": "2025-04-22 21:37:22 -0500", "tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp": "2025-02-10 23:30:47 -0700", "tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_binary_tree.test.cpp": "2025-02-10 14:50:36 -0700", -"tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_k_ary_tree.test.cpp": "2025-06-03 13:37:20 -0600", -"tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2025-06-03 13:37:20 -0600", -"tests/library_checker_aizu_tests/monotonic_stack_related/max_rect_histogram.test.cpp": "2025-06-03 13:37:20 -0600", +"tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_k_ary_tree.test.cpp": "2025-08-03 18:39:58 -0600", +"tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2025-08-03 18:39:58 -0600", +"tests/library_checker_aizu_tests/monotonic_stack_related/max_rect_histogram.test.cpp": "2025-08-03 18:39:58 -0600", "tests/library_checker_aizu_tests/strings/kmp.test.cpp": "2024-12-14 19:50:29 -0600", "tests/library_checker_aizu_tests/strings/lcp_array.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/strings/lcp_query_palindrome.test.cpp": "2025-02-10 14:50:36 -0700", @@ -123,7 +123,7 @@ "tests/library_checker_aizu_tests/strings/sa_cmp.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/strings/sa_sort_pairs.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/strings/single_matching_bs.test.cpp": "2025-02-10 14:50:36 -0700", -"tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2025-06-03 13:37:20 -0600", +"tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2025-08-03 18:39:58 -0600", "tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/strings/trie.test.cpp": "2024-12-05 10:41:42 -0600", "tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2024-12-14 19:50:29 -0600", diff --git a/library/data_structures/uncommon/linear_rmq.hpp b/library/data_structures/uncommon/linear_rmq.hpp index 503308a8..d7f05ea3 100644 --- a/library/data_structures/uncommon/linear_rmq.hpp +++ b/library/data_structures/uncommon/linear_rmq.hpp @@ -1,10 +1,10 @@ #pragma once //! https://codeforces.com/blog/entry/125371?#comment-1173604 //! @code -//! linear_rmq rmq1(a, less());//right-most min -//! linear_rmq rmq2(a, less_equal());//left-most min -//! linear_rmq rmq3(a, greater());//right-most max -//! linear_rmq rmq4(a, greater_equal());//left-most max +//! linear_rmq rmq1(a, less()); //right-most min +//! linear_rmq rmq2(a, less_equal()); //left-most min +//! linear_rmq rmq3(a, greater()); //right-most max +//! linear_rmq rmq4(a, greater_equal()); //left-most max //! linear_rmq rmq5(a, [&](auto& x, auto& y) { //! return x < y; //! }); @@ -12,38 +12,36 @@ //! @time O(n + q) //! @space O(n) template struct linear_rmq { + int n; vector a; F cmp; - vi head; - vector> t; + vi in, asc, head; linear_rmq(const vector& a, F cmp): - a(a), cmp(cmp), head(sz(a) + 1), t(sz(a)) { + n(sz(a)), a(a), cmp(cmp), in(n), asc(n), head(n + 1) { vi st{-1}; - for (int i = 0; i <= sz(a); i++) { - int prev = -1; - while (st.back() != -1 && - (i == sz(a) || !cmp(a[st.back()], a[i]))) { - if (prev != -1) head[prev] = st.back(); - int pw2 = 1 << __lg((end(st)[-2] + 1) ^ i); - t[st.back()][0] = prev = i & -pw2; + rep(i, 0, n + 1) { + int prev = 0; + while (sz(st) > 1 && + (i == n || !cmp(a[st.back()], a[i]))) { + head[prev] = st.back(); + auto k = end(st)[-2] + 1u, b = bit_floor(k ^ i); + in[st.back()] = prev = i & -b, asc[k] |= b; st.pop_back(); - t[st.back() + 1][1] |= pw2; } - if (prev != -1) head[prev] = i; - st.push_back(i); + st.push_back(head[prev] = i); } - rep(i, 1, sz(a)) t[i][1] = - (t[i][1] | t[i - 1][1]) & -(t[i][0] & -t[i][0]); + rep(i, 1, n) asc[i] = + (asc[i] | asc[i - 1]) & -(in[i] & -in[i]); } - int query_idx(int l, int r) { // [l, r] - if (unsigned j = t[l][0] ^ t[r][0]; j) { - j = t[l][1] & t[r][1] & -bit_floor(j); - if (unsigned k = t[l][1] ^ j; k) - k = bit_floor(k), l = head[(t[l][0] & -k) | k]; - if (unsigned k = t[r][1] ^ j; k) - k = bit_floor(k), r = head[(t[r][0] & -k) | k]; + int idx(int l, int r) { // [l, r] + if (unsigned j = in[l] ^ in[r]; j) { + j = asc[l] & asc[r] & -bit_floor(j); + if (unsigned k = asc[l] ^ j; k) + k = bit_floor(k), l = head[(in[l] & -k) | k]; + if (unsigned k = asc[r] ^ j; k) + k = bit_floor(k), r = head[(in[r] & -k) | k]; } return cmp(a[l], a[r]) ? l : r; } - T query(int l, int r) { return a[query_idx(l, r)]; } + T query(int l, int r) { return a[idx(l, r)]; } }; diff --git a/library/data_structures/uncommon/permutation_tree.hpp b/library/data_structures/uncommon/permutation_tree.hpp index fbd98057..e5553677 100644 --- a/library/data_structures/uncommon/permutation_tree.hpp +++ b/library/data_structures/uncommon/permutation_tree.hpp @@ -37,8 +37,8 @@ struct perm_tree { linear_rmq rmq_min(a_inv, less()); linear_rmq rmq_max(a_inv, greater()); rep(i, 1, n) { - mn_i[i] = a_inv[rmq_min.query_idx(a[i - 1], a[i])]; - mx_i[i] = a_inv[rmq_max.query_idx(a[i - 1], a[i])]; + mn_i[i] = a_inv[rmq_min.idx(a[i - 1], a[i])]; + mx_i[i] = a_inv[rmq_max.idx(a[i - 1], a[i])]; } } rep(i, 0, n) allocate(i, a[i], 1, 0, {}); diff --git a/tests/.config/.cppcheck_suppression_list b/tests/.config/.cppcheck_suppression_list index b49f37a0..a5be8a60 100644 --- a/tests/.config/.cppcheck_suppression_list +++ b/tests/.config/.cppcheck_suppression_list @@ -62,3 +62,4 @@ unusedFunction:../kactl/content/number-theory/ModPow.h:13 unusedFunction:../kactl/stress-tests/utilities/genTree.h:49 assertWithSideEffect:library_checker_aizu_tests/math/xor_basis_intersection.test.cpp:27 assertWithSideEffect:library_checker_aizu_tests/math/xor_basis_intersection.test.cpp:36 +containerOutOfBounds:../library/data_structures/uncommon/permutation_tree.hpp:85 diff --git a/tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp b/tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp index 90a06dcf..fb3de419 100644 --- a/tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp +++ b/tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp @@ -16,21 +16,20 @@ int main() { while (q--) { int l, r; cin >> l >> r; - int idx_right_min = rmq_less.query_idx(l, r - 1); + int idx_right_min = rmq_less.idx(l, r - 1); assert(idx_right_min + 1 == r || rmq_less.query(idx_right_min + 1, r - 1) > a[idx_right_min]); assert(l <= idx_right_min && idx_right_min < r); assert(rmq_less.query(l, r - 1) == a[idx_right_min]); - assert( - idx_right_min == rmq_greater.query_idx(l, r - 1)); - int idx_left_min = rmq_less_equal.query_idx(l, r - 1); + assert(idx_right_min == rmq_greater.idx(l, r - 1)); + int idx_left_min = rmq_less_equal.idx(l, r - 1); assert(l == idx_left_min || rmq_less_equal.query(l, idx_left_min - 1) > a[idx_left_min]); assert(l <= idx_left_min && idx_left_min < r); - assert(idx_left_min == - rmq_greater_equal.query_idx(l, r - 1)); + assert( + idx_left_min == rmq_greater_equal.idx(l, r - 1)); assert(a[idx_right_min] == a[idx_left_min]); assert(idx_left_min <= idx_right_min); cout << a[idx_right_min] << '\n'; diff --git a/tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp index 8b97202f..2dbec0e4 100644 --- a/tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp +++ b/tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp @@ -13,7 +13,7 @@ void test_all_subarrays(const vector& a) { linear_rmq lin_rmq(a, less()); for (int l = 0; l < n; l++) { for (int r = l + 1; r <= n; r++) { - int idx_min = lin_rmq.query_idx(l, r - 1); + int idx_min = lin_rmq.idx(l, r - 1); assert(l <= idx_min && idx_min < r); assert(a[idx_min] == rmq.query(l, r)); assert(a[idx_min] == dis_rmq.query(l, r));