diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index b41026b77..c8da6b3aa 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -20,8 +20,6 @@ "tests/library_checker_aizu_tests/data_structures/distinct_query.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/data_structures/dsu.test.cpp": "2026-01-22 10:08:22 -0700", "tests/library_checker_aizu_tests/data_structures/dsu_bipartite.test.cpp": "2026-01-18 02:20:40 +0000", -"tests/library_checker_aizu_tests/data_structures/dsu_restorable.test.cpp": "2026-01-18 02:20:40 +0000", -"tests/library_checker_aizu_tests/data_structures/dsu_segtree_undo_trick.test.cpp": "2026-01-23 04:31:29 +0000", "tests/library_checker_aizu_tests/data_structures/implicit_seg_tree.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/data_structures/kd_bit_1d.test.cpp": "2026-02-19 18:06:52 -0700", "tests/library_checker_aizu_tests/data_structures/kruskal_tree_aizu.test.cpp": "2026-01-18 02:20:40 +0000", @@ -39,7 +37,6 @@ "tests/library_checker_aizu_tests/data_structures/persistent_queue_tree.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/data_structures/persistent_seg_tree.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/data_structures/pq_ds_undo_sliding_window.test.cpp": "2026-01-18 02:20:40 +0000", -"tests/library_checker_aizu_tests/data_structures/pq_ds_undo_with_dsu.test.cpp": "2026-01-18 02:20:40 +0000", "tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp": "2026-01-22 10:08:22 -0700", "tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/data_structures/rmq_sparse_table.test.cpp": "2026-01-18 11:15:41 +0000", @@ -71,10 +68,9 @@ "tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp": "2026-01-22 10:08:22 -0700", "tests/library_checker_aizu_tests/graphs/strongly_connected_components_aizu.test.cpp": "2026-01-17 13:05:42 -0700", "tests/library_checker_aizu_tests/graphs/strongly_connected_components_lib_checker.test.cpp": "2026-01-17 13:05:42 -0700", -"tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp": "2026-01-18 02:20:40 +0000", +"tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp": "2026-02-27 11:11:58 -0700", "tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/handmade_tests/dsu.test.cpp": "2026-01-22 10:08:22 -0700", -"tests/library_checker_aizu_tests/handmade_tests/dsu_size.test.cpp": "2026-01-18 02:20:40 +0000", "tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2025-09-07 15:50:55 -0600", "tests/library_checker_aizu_tests/handmade_tests/fib_matrix_expo.test.cpp": "2026-01-28 21:48:16 -0700", "tests/library_checker_aizu_tests/handmade_tests/functional_graph.test.cpp": "2025-08-06 16:18:37 -0600", @@ -90,6 +86,7 @@ "tests/library_checker_aizu_tests/handmade_tests/sa_find_subarray.test.cpp": "2026-01-27 18:11:48 +0000", "tests/library_checker_aizu_tests/handmade_tests/seg_tree_find.test.cpp": "2026-01-23 04:31:29 +0000", "tests/library_checker_aizu_tests/handmade_tests/seg_tree_find_small.test.cpp": "2026-01-23 04:31:29 +0000", +"tests/library_checker_aizu_tests/handmade_tests/seg_tree_midpoint.test.cpp": "2026-02-27 11:11:58 -0700", "tests/library_checker_aizu_tests/loops/chooses.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/loops/quotients.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/loops/submasks.test.cpp": "2025-02-10 14:50:36 -0700", diff --git a/library/dsu/dsu_restorable.hpp b/library/dsu/dsu_restorable.hpp deleted file mode 100644 index e06d411da..000000000 --- a/library/dsu/dsu_restorable.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -//! https://github.com/ucf-programming-team/hackpack-cpp/blob/master/content/data-structures/DSURestorable.h -//! DSU without path compression, so non-amortized. Most -//! operations are O(log n) -struct dsu_restorable { - int num_sets; - vi p; - vector subtree; - vector>> st; - dsu_restorable(int n): - num_sets(n), p(n, -1), subtree(n) {} - int find(int v) { - while (p[v] >= 0) v = p[v]; - return v; - } - bool join(int u, int v) { - st.emplace_back(); - if ((u = find(u)) == (v = find(v))) return 0; - if (p[u] > p[v]) swap(u, v); - st.back() = {u, v, p[v]}; - p[u] += p[v], p[v] = u, subtree[u] += subtree[v], - num_sets--; - return 1; - } - void undo() { - if (auto b = st.back()) { - auto [u, v, sz_v] = *b; - num_sets++, subtree[u] -= subtree[v], p[v] = sz_v, - p[u] -= p[v]; - } - st.pop_back(); - } - int size(int v) { return -p[find(v)]; } - bool same_set(int u, int v) { - return find(u) == find(v); - } - ll sum(int v) { return subtree[find(v)]; } - void add(int v, int d) { - while (v >= 0) subtree[v] += d, v = p[v]; - } -}; diff --git a/tests/library_checker_aizu_tests/data_structures/dsu_restorable.test.cpp b/tests/library_checker_aizu_tests/data_structures/dsu_restorable.test.cpp deleted file mode 100644 index 2dce308ff..000000000 --- a/tests/library_checker_aizu_tests/data_structures/dsu_restorable.test.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/persistent_unionfind" -#include "../template.hpp" -#include "../../../library/dsu/dsu_restorable.hpp" -int main() { - cin.tie(0)->sync_with_stdio(0); - int n, q; - cin >> n >> q; - vector> childs(q + 1), queries(q + 1); - vector query_u(q + 1), query_v(q + 1); - for (int i = 1; i <= q; i++) { - int type, k; - cin >> type >> k >> query_u[i] >> query_v[i]; - k++; - if (type == 0) childs[k].push_back(i); - else { - assert(type == 1); - queries[k].push_back(i); - } - } - vector res(q + 1, -1); - { - dsu_restorable dsu(n); - auto dfs = [&](auto&& self, int u) -> void { - for (auto idx : queries[u]) - res[idx] = - dsu.same_set(query_u[idx], query_v[idx]); - for (auto child : childs[u]) { - dsu.join(query_u[child], query_v[child]); - self(self, child); - dsu.undo(); - } - }; - dfs(dfs, 0); - } - for (int i = 1; i <= q; i++) - if (res[i] != -1) cout << res[i] << "\n"; - return 0; -} diff --git a/tests/library_checker_aizu_tests/data_structures/dsu_segtree_undo_trick.test.cpp b/tests/library_checker_aizu_tests/data_structures/dsu_segtree_undo_trick.test.cpp deleted file mode 100644 index f9ea716d8..000000000 --- a/tests/library_checker_aizu_tests/data_structures/dsu_segtree_undo_trick.test.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/dynamic_graph_vertex_add_component_sum" -#include "../template.hpp" -#include "../../../library//dsu/dsu_restorable.hpp" -#include "../../../library/data_structures_[l,r)/lazy_seg_tree.hpp" -int main() { - cin.tie(0)->sync_with_stdio(0); - int n, q; - cin >> n >> q; - dsu_restorable dsu(n); - for (int i = 0; i < n; i++) cin >> dsu.subtree[i]; - vector>> tree(2 * q); - auto add_edge = [&](auto&& self, int l, int r, - int node_u, int node_v, int tl, int tr, - int v) -> void { - if (r <= tl || tr <= l) return; - if (l <= tl && tr <= r) { - tree[v].emplace_back(node_u, node_v); - return; - } - int tm = split(tl, tr); - self(self, l, r, node_u, node_v, tl, tm, 2 * v); - self(self, l, r, node_u, node_v, tm, tr, 2 * v + 1); - }; - struct query { - int type, v, x; - }; - vector queries(q); - { - map, int> insert_time; - for (int i = 0; i < q; i++) { - int type; - cin >> type; - if (type == 0) { - int u, v; - cin >> u >> v; - if (u > v) swap(u, v); - assert(!insert_time.contains({u, v})); - insert_time[{u, v}] = i; - } else if (type == 1) { - int u, v; - cin >> u >> v; - if (u > v) swap(u, v); - assert(insert_time.contains({u, v})); - add_edge(add_edge, insert_time[{u, v}], i, u, v, 0, - q, 1); - insert_time.erase({u, v}); - } else if (type == 2) { - int v, x; - cin >> v >> x; - queries[i] = {2, v, x}; - } else { - assert(type == 3); - int v; - cin >> v; - queries[i] = {3, v, -1}; - } - } - for (auto [edge, i_time] : insert_time) - add_edge(add_edge, i_time, q, edge.first, - edge.second, 0, q, 1); - } - auto dfs = [&](auto&& self, int tl, int tr, - int v) -> void { - for (auto [node_u, node_v] : tree[v]) - dsu.join(node_u, node_v); - assert((v >= q) == ((tr - tl) == 1)); - if (v >= q) { // leaf node - const int depth_leaf = __lg(v), - max_depth = __lg(2 * q - 1); - if (tl == 0) { // left-most leaf - assert(v == (1 << max_depth)); - assert(depth_leaf == max_depth); - } - assert(q <= v && v < 2 * q); - assert(depth_leaf == max_depth || - depth_leaf == max_depth - 1); - if ((q & (q - 1)) == 0) - assert(depth_leaf == max_depth); - if (queries[tl].type == 2) - dsu.add(queries[tl].v, queries[tl].x); - else if (queries[tl].type == 3) - cout << dsu.sum(queries[tl].v) << '\n'; - } else { - assert(1 <= v && v < q); - if (((tr - tl) & (tr - tl - 1)) == 0) - assert(split(tl, tr) == (tl + tr) / 2); - { - int pow_2 = 1 << __lg(tr - tl); - if (tl + pow_2 < tr - pow_2 / 2) { - assert(pow_2 != tr - tl); - assert(pow_2 / 2 < tr - tl - pow_2 && - tr - tl - pow_2 < pow_2); - assert(pow_2 <= 2 * (tr - tl - pow_2) - 1 && - 2 * (tr - tl - pow_2) - 1 < 2 * pow_2 - 1); - assert(__lg(pow_2) == - __lg(2 * ((tr - tl) - pow_2) - 1) && - __lg(pow_2) == __lg(2 * pow_2 - 1)); - } else if (pow_2 < tr - tl) { - assert(pow_2 / 2 < tr - tl - pow_2 / 2 && - tr - tl - pow_2 / 2 <= pow_2); - assert( - pow_2 <= 2 * ((tr - tl) - pow_2 / 2) - 1 && - 2 * ((tr - tl) - pow_2 / 2) - 1 <= - 2 * pow_2 - 1); - assert(__lg(2 * (tr - tl - pow_2 / 2) - 1) == - __lg(2 * pow_2 - 1)); - assert(__lg(2 * ((tr - tl) - pow_2 / 2) - 1) == - __lg(pow_2)); - assert( - __lg(pow_2) == 1 + __lg(2 * (pow_2 / 2) - 1)); - } - } - int tm = split(tl, tr); - // in particular, this tests that split works with - // negatives - assert(split(tl - 1234, tr - 1234) == tm - 1234); - assert(split(tl - 1, tr - 1) == tm - 1); - assert(split(tl + 50, tr + 50) == tm + 50); - self(self, tl, tm, 2 * v); - self(self, tm, tr, 2 * v + 1); - } - for (int i = 0; i < sz(tree[v]); i++) dsu.undo(); - }; - dfs(dfs, 0, q, 1); - return 0; -} diff --git a/tests/library_checker_aizu_tests/data_structures/pq_ds_undo_with_dsu.test.cpp b/tests/library_checker_aizu_tests/data_structures/pq_ds_undo_with_dsu.test.cpp deleted file mode 100644 index 16ed0c123..000000000 --- a/tests/library_checker_aizu_tests/data_structures/pq_ds_undo_with_dsu.test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/dynamic_graph_vertex_add_component_sum" -// since _GLIBCXX_DEBUG causes std::map insert/erase -// operations to be O(n) -#undef _GLIBCXX_DEBUG -#include "../template.hpp" -#include "../../../library/dsu/dsu_restorable.hpp" -#include "../../../library/data_structures_[l,r)/uncommon/priority_queue_of_updates.hpp" -int main() { - cin.tie(0)->sync_with_stdio(0); - int n, q; - cin >> n >> q; - vector initial_values(n); - for (int i = 0; i < n; i++) cin >> initial_values[i]; - vector time_remove(q, -1); - struct query { - int type, u, v, x; - }; - vector queries(q); - { - map, int> insert_time; - for (int i = 0; i < q; i++) { - int type; - cin >> type; - if (type == 0) { - int u, v; - cin >> u >> v; - if (u > v) swap(u, v); - assert(!insert_time.contains({u, v})); - insert_time[{u, v}] = i; - queries[i] = {type, u, v, -1}; - } else if (type == 1) { - int u, v; - cin >> u >> v; - if (u > v) swap(u, v); - assert(insert_time.contains({u, v})); - time_remove[insert_time[{u, v}]] = i; - insert_time.erase({u, v}); - queries[i] = {type, -1, -1, -1}; - } else if (type == 2) { - int v, x; - cin >> v >> x; - queries[i] = {type, -1, v, x}; - } else { - assert(type == 3); - int v; - cin >> v; - queries[i] = {type, -1, v, -1}; - } - } - } - dsu_restorable dsu_r(n); - pq_updates pq(dsu_r); - for (int i = 0; i < n; i++) - pq.ds.add(i, initial_values[i]); - int curr_priority_counter = -q; - for (int i = 0; i < q; i++) { - int type = queries[i].type; - if (type == 0) { - int u = queries[i].u, v = queries[i].v; - int curr_pri; - if (time_remove[i] == -1) - curr_pri = curr_priority_counter--; - else curr_pri = -time_remove[i]; - pq.push_update(u, v, curr_pri); - } else if (type == 1) pq.pop_update(); - else if (type == 2) { - int v = queries[i].v, x = queries[i].x; - pq.ds.add(v, x); - } else { - assert(type == 3); - int v = queries[i].v; - cout << pq.ds.sum(v) << '\n'; - } - } - return 0; -} diff --git a/tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp b/tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp index be5f84be0..b2af2ee6b 100644 --- a/tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp +++ b/tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp @@ -2,7 +2,7 @@ "https://judge.yosupo.jp/problem/two_edge_connected_components" #include "../template.hpp" #include "../../../library/graphs/uncommon/bridge_tree.hpp" -#include "../../../library/dsu/dsu_restorable.hpp" +#include "../../../library/dsu/dsu.hpp" int main() { cin.tie(0)->sync_with_stdio(0); int n, m; @@ -33,7 +33,7 @@ int main() { accumulate(begin(is_br), end(is_br), 0); assert(sum_deg % 2 == 0 && sum_deg / 2 == cnt_bridges); } - dsu_restorable dsu(n); + DSU dsu(n); int num_sets_dsu = n; for (int i = 0; i < m; i++) { if (!is_br[i]) { @@ -45,12 +45,11 @@ int main() { for (int i = 0; i < m; i++) { if (is_br[i]) { auto [u, v] = edges[i]; - bool same_set = dsu.same_set(u, v); - assert(!same_set); + assert(dsu.f(u) != dsu.f(v)); } } for (int i = 0; i < n; i++) { - int par_of_cc = dsu.find(i); + int par_of_cc = dsu.f(i); assert(br_id[i] == br_id[par_of_cc]); } for (int i = 0; i < m; i++) { diff --git a/tests/library_checker_aizu_tests/handmade_tests/dsu_size.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/dsu_size.test.cpp deleted file mode 100644 index 3e8b594e3..000000000 --- a/tests/library_checker_aizu_tests/handmade_tests/dsu_size.test.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#define PROBLEM \ - "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" -#include "../template.hpp" -#include "../../../library/contest/random.hpp" -#include "../../../library/dsu/dsu_restorable.hpp" -int main() { - cin.tie(0)->sync_with_stdio(0); - for (int n = 1; n < 100; n++) { - dsu_restorable dsu(n); - vector> adj(n); - vector> edge_st; - for (int q = 0; q < 100; q++) { - int type = rnd(0, 2); - if (type == 0) { - int u = rnd(0, n - 1), v = rnd(0, n - 1); - dsu.join(u, v); - adj[u].push_back(v); - adj[v].push_back(u); - edge_st.emplace_back(u, v); - } else if (type == 1) { - vector> comps; - vector vis(n); - auto dfs = [&](auto&& self, int node) -> void { - comps.back().push_back(node); - for (auto next : adj[node]) - if (!vis[next]) { - vis[next] = true; - self(self, next); - } - }; - for (int i = 0; i < n; i++) { - if (!vis[i]) { - comps.emplace_back(); - vis[i] = true; - dfs(dfs, i); - } - } - assert(sz(comps) == dsu.num_sets); - for (auto& cc : comps) - for (auto node : cc) - assert(dsu.size(node) == sz(cc)); - } else if (!empty(edge_st)) { - auto [u, v] = edge_st.back(); - edge_st.pop_back(); - assert(adj[u].back() == v && adj[v].back() == u); - adj[u].pop_back(); - adj[v].pop_back(); - dsu.undo(); - } - } - } - cout << "Hello World\n"; - return 0; -} diff --git a/tests/library_checker_aizu_tests/handmade_tests/seg_tree_midpoint.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/seg_tree_midpoint.test.cpp new file mode 100644 index 000000000..7f3d84bdf --- /dev/null +++ b/tests/library_checker_aizu_tests/handmade_tests/seg_tree_midpoint.test.cpp @@ -0,0 +1,67 @@ +#define PROBLEM \ + "https://onlinejudge.u-aizu.ac.jp/problems/ITP1_1_A" +#include "../template.hpp" +#include "../../../library/data_structures_[l,r)/seg_tree_midpoint.hpp" +int main() { + cin.tie(0)->sync_with_stdio(0); + for (int n = 1; n < 5000; n++) { + auto dfs = [&](auto&& self, int tl, int tr, + int v) -> void { + assert((v >= n) == ((tr - tl) == 1)); + if (v >= n) { // leaf node + const int depth_leaf = __lg(v), + max_depth = __lg(2 * n - 1); + if (tl == 0) { // left-most leaf + assert(v == (1 << max_depth)); + assert(depth_leaf == max_depth); + } + assert(n <= v && v < 2 * n); + assert(depth_leaf == max_depth || + depth_leaf == max_depth - 1); + if ((n & (n - 1)) == 0) + assert(depth_leaf == max_depth); + } else { + assert(1 <= v && v < n); + if (((tr - tl) & (tr - tl - 1)) == 0) + assert(split(tl, tr) == (tl + tr) / 2); + { + int pow_2 = 1 << __lg(tr - tl); + if (tl + pow_2 < tr - pow_2 / 2) { + assert(pow_2 != tr - tl); + assert(pow_2 / 2 < tr - tl - pow_2 && + tr - tl - pow_2 < pow_2); + assert(pow_2 <= 2 * (tr - tl - pow_2) - 1 && + 2 * (tr - tl - pow_2) - 1 < 2 * pow_2 - 1); + assert(__lg(pow_2) == + __lg(2 * ((tr - tl) - pow_2) - 1) && + __lg(pow_2) == __lg(2 * pow_2 - 1)); + } else if (pow_2 < tr - tl) { + assert(pow_2 / 2 < tr - tl - pow_2 / 2 && + tr - tl - pow_2 / 2 <= pow_2); + assert( + pow_2 <= 2 * ((tr - tl) - pow_2 / 2) - 1 && + 2 * ((tr - tl) - pow_2 / 2) - 1 <= + 2 * pow_2 - 1); + assert(__lg(2 * (tr - tl - pow_2 / 2) - 1) == + __lg(2 * pow_2 - 1)); + assert(__lg(2 * ((tr - tl) - pow_2 / 2) - 1) == + __lg(pow_2)); + assert(__lg(pow_2) == + 1 + __lg(2 * (pow_2 / 2) - 1)); + } + } + int tm = split(tl, tr); + // in particular, this tests that split works with + // negatives + assert(split(tl - 1234, tr - 1234) == tm - 1234); + assert(split(tl - 1, tr - 1) == tm - 1); + assert(split(tl + 50, tr + 50) == tm + 50); + self(self, tl, tm, 2 * v); + self(self, tm, tr, 2 * v + 1); + } + }; + dfs(dfs, 0, n, 1); + } + cout << "Hello World\n"; + return 0; +}