Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .verify-helper/timestamps.remote.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,20 @@
"tests/library_checker_aizu_tests/data_structures/disjoint_rmq_inc_lines.test.cpp": "2026-01-18 11:15:41 +0000",
"tests/library_checker_aizu_tests/data_structures/disjoint_rmq_inc_sum.test.cpp": "2026-01-18 11:15:41 +0000",
"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/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",
"tests/library_checker_aizu_tests/data_structures/kth_smallest_pst.test.cpp": "2026-01-18 11:15:41 +0000",
"tests/library_checker_aizu_tests/data_structures/kth_smallest_wavelet_matrix.test.cpp": "2026-02-04 02:50:53 +0000",
"tests/library_checker_aizu_tests/data_structures/lazy_segment_tree.test.cpp": "2026-01-23 04:31:29 +0000",
"tests/library_checker_aizu_tests/data_structures/lazy_segment_tree_constructor.test.cpp": "2026-01-23 04:31:29 +0000",
"tests/library_checker_aizu_tests/data_structures/lazy_segment_tree_inc.test.cpp": "2026-02-05 13:02:29 -0700",
"tests/library_checker_aizu_tests/data_structures/lazy_segment_tree_inc_constructor.test.cpp": "2026-02-05 13:02:29 -0700",
"tests/library_checker_aizu_tests/data_structures/line_tree_aizu.test.cpp": "2026-01-18 11:15:41 +0000",
"tests/library_checker_aizu_tests/data_structures/line_tree_lib_checker.test.cpp": "2026-01-18 02:20:40 +0000",
"tests/library_checker_aizu_tests/data_structures/merge_sort_tree.test.cpp": "2026-01-18 11:04:58 +0000",
"tests/library_checker_aizu_tests/data_structures/mode_query.test.cpp": "2026-01-18 02:20:40 +0000",
"tests/library_checker_aizu_tests/data_structures/permutation_tree.test.cpp": "2026-01-18 11:15:41 +0000",
"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/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",
"tests/library_checker_aizu_tests/data_structures/rmq_sparse_table_inc.test.cpp": "2026-01-18 11:15:41 +0000",
Expand All @@ -47,6 +41,12 @@
"tests/library_checker_aizu_tests/data_structures/simple_tree_inc_walk.test.cpp": "2026-02-16 16:56:58 -0700",
"tests/library_checker_aizu_tests/data_structures/simple_tree_line.test.cpp": "2026-02-14 20:58:21 +0000",
"tests/library_checker_aizu_tests/data_structures/simple_tree_walk.test.cpp": "2026-02-14 20:58:21 +0000",
"tests/library_checker_aizu_tests/dsu/dsu.test.cpp": "2026-02-27 11:50:42 -0700",
"tests/library_checker_aizu_tests/dsu/dsu_bipartite.test.cpp": "2026-02-27 11:58:10 -0700",
"tests/library_checker_aizu_tests/dsu/kruskal_tree_aizu.test.cpp": "2026-02-27 11:50:42 -0700",
"tests/library_checker_aizu_tests/dsu/line_tree_aizu.test.cpp": "2026-02-27 11:56:18 -0700",
"tests/library_checker_aizu_tests/dsu/line_tree_lib_checker.test.cpp": "2026-02-27 11:56:18 -0700",
"tests/library_checker_aizu_tests/dsu/range_parallel_dsu.test.cpp": "2026-02-27 14:31:41 -0700",
"tests/library_checker_aizu_tests/flow/dinic_aizu.test.cpp": "2024-11-17 14:04:03 -0600",
"tests/library_checker_aizu_tests/flow/hungarian.test.cpp": "2024-11-17 14:04:03 -0600",
"tests/library_checker_aizu_tests/flow/min_cost_max_flow.test.cpp": "2024-12-05 10:41:42 -0600",
Expand Down
34 changes: 14 additions & 20 deletions library/dsu/dsu_bipartite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,28 @@
//! DSU with support for parity of path to root for online
//! bipartite check
struct dsu_bipartite {
int num_sets;
vi p, is_bi, parity;
dsu_bipartite(int n):
num_sets(n), p(n, -1), is_bi(n, 1), parity(n) {}
int find(int v) {
dsu_bipartite(int n): p(n, -1), is_bi(n, 1), parity(n) {}
int f(int v) {
if (p[v] < 0) return v;
int root = find(p[v]);
int root = f(p[v]);
parity[v] ^= parity[p[v]];
return p[v] = root;
}
bool join(int u, int v) {
int root_u = find(u), root_v = find(v);
if (root_u == root_v) {
if (parity[u] == parity[v]) is_bi[root_u] = 0;
int root_u = f(u), root_v = f(v);
int new_parity = parity[v] ^ parity[u];
u = root_u, v = root_v;
if (u == v) {
is_bi[u] &= new_parity;
return 0;
}
if (p[root_u] > p[root_v]) {
swap(u, v);
swap(root_u, root_v);
}
is_bi[root_u] &= is_bi[root_v];
parity[root_v] = parity[v] ^ 1 ^ parity[u];
p[root_u] += p[root_v], p[root_v] = root_u, num_sets--;
if (p[u] > p[v]) swap(u, v);
is_bi[u] &= is_bi[v];
parity[v] = new_parity ^ 1;
p[u] += p[v], p[v] = u;
return 1;
}
int size(int v) { return -p[find(v)]; }
bool same_set(int u, int v) {
return find(u) == find(v);
}
bool is_bipartite(int v) { return is_bi[find(v)]; }
int size(int v) { return -p[f(v)]; }
bool is_bipartite(int v) { return is_bi[f(v)]; }
};
6 changes: 2 additions & 4 deletions library/dsu/kruskal_tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ struct kr_tree {
vi p;
vector<vi> adj;
kr_tree(int n): id(n), p(2 * n, -1), adj(2 * n) {}
int find(int v) {
return p[v] < 0 ? v : p[v] = find(p[v]);
}
int f(int v) { return p[v] < 0 ? v : p[v] = f(p[v]); }
bool join(int u, int v) {
if ((u = find(u)) == (v = find(v))) return 0;
if ((u = f(u)) == (v = f(v))) return 0;
return adj[p[u] = p[v] = id++] = {u, v}, 1;
}
};
14 changes: 6 additions & 8 deletions library/dsu/line_tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
//! ranges::sort(w_eds);
//! line_tree lt(n);
//! for (auto [w, u, v] : w_eds) lt.join(u, v);
//! for (int v = lt.find(0); v != -1;) {
//! for (int v = lt.f(0); v != -1;) {
//! auto [next, e_id] = lt.edge[v];
//! int w = w_eds[e_id][0];
//! //
//! v = next;
//! }
//! @endcode
//! lt.find(v) = head of linked list
//! lt.f(v) = head of linked list
//! of component containing v
//! @time O(n + m * \alpha(n))
//! @space O(n + m)
Expand All @@ -22,16 +22,14 @@ struct line_tree {
line_tree(int n): p(n, -1), last(n), edge(n, {-1, -1}) {
iota(all(last), 0);
}
int size(int v) { return -p[find(v)]; }
int find(int v) {
return p[v] < 0 ? v : p[v] = find(p[v]);
}
int size(int v) { return -p[f(v)]; }
int f(int v) { return p[v] < 0 ? v : p[v] = f(p[v]); }
bool join(int u, int v) {
u = find(u), v = find(v), id++;
u = f(u), v = f(v), id++;
if (u == v) return 0;
if (p[u] < p[v]) swap(u, v);
p[v] += p[u], p[u] = v;
edge[exchange(last[v], last[u])] = {u, id - 1};
edge[last[v]] = {u, id - 1}, last[v] = last[u];
return 1;
}
};
34 changes: 13 additions & 21 deletions library/dsu/range_parallel_dsu.hpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
#pragma once
#include "dsu.hpp"
//! Given l1,l2,len; joins (l1,l2), (l1+1,l2+1),
//! ..., (l1+len-1,l2+len-1)
//! Given u,v,len; joins (u,v), (u+1,v+1),
//! ..., (u+len-1,v+len-1)
//! `f` is called at most n-1 times
//! @time O(n*log(n)*\alpha(n) + q)
//! @space O(n log n)
struct rp_dsu {
vector<DSU> dsus;
rp_dsu(int n): dsus(bit_width(unsigned(n)), DSU(n)) {}
void join(int l1, int l2, int len, const auto& f) {
if (len == 0) return;
int lg = __lg(len);
join_impl(lg, l1, l2, f);
join_impl(lg, l1 + len - (1 << lg),
l2 + len - (1 << lg), f);
rp_dsu(int n): dsus(bit_width(n + 0u), DSU(n)) {}
void join(int u, int v, int len, const auto& f) {
int i = __lg(len);
join(u, v, f, i);
join(u + len - (1 << i), v + len - (1 << i), f, i);
}
void join_impl(int lvl, int u, int v, const auto& f) {
if (lvl == 0) {
u = dsus[0].f(u);
v = dsus[0].f(v);
if (!dsus[0].join(v, u)) return;
int w = dsus[0].f(u);
return f(w, u ^ v ^ w);
}
if (!dsus[lvl].join(u, v)) return;
join_impl(lvl - 1, u, v, f);
join_impl(lvl - 1, u + (1 << (lvl - 1)),
v + (1 << (lvl - 1)), f);
void join(int u, int v, const auto& f, int i) {
if (!dsus[i].join(u, v)) return;
if (i == 0) return f(u, v);
i--;
join(u, v, f, i);
join(u + (1 << i), v + (1 << i), f, i);
}
};
26 changes: 16 additions & 10 deletions library/dsu/range_parallel_equivalence_classes.hpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
#pragma once
#include "dsu.hpp"
//! Given triplets (l1,l2,len); joins (l1,l2),
//! (l1+1,l2+1), ..., (l1+len-1,l2+len-1)
//! @code
//! vector<vector<pii>> joins(n + 1);
//! joins[len].emplace_back(u, v);
//! // it does:
//! // dsu.join(u + 0, v + 0);
//! // dsu.join(u + 1, v + 1);
//! // dsu.join(u + 2, v + 2);
//! // ...
//! // dsu.join(u + len - 1, v + len - 1);
//! DSU dsu = get_rp_dsu(joins, n);
//! @endcode
//! @time O((n + q) * \alpha(n))
//! @space O(n + q)
DSU get_rp_dsu(const vector<array<int, 3>>& rests, int n) {
vector<vector<pii>> rests_by_len(n + 1);
for (auto [l1, l2, len] : rests)
rests_by_len[len].emplace_back(l1, l2);
DSU get_rp_dsu(vector<vector<pii>>& joins, int n) {
DSU dsu(n);
for (int len = n; len > 0; len--)
for (auto [l1, l2] : rests_by_len[len])
if (dsu.join(l1, l2))
rests_by_len[len - 1].emplace_back(l1 + 1, l2 + 1);
for (int i = n; i; i--)
for (auto [u, v] : joins[i])
if (dsu.join(u, v))
joins[i - 1].emplace_back(u + 1, v + 1);
return dsu;
}
2 changes: 1 addition & 1 deletion tests/.config/.cppcheck_suppression_list
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ syntaxError:../library/math/prime_sieve/mobius.hpp:6
syntaxError:../library/trees/lca_rmq/iterate_subtree.hpp:6
knownConditionTrueFalse:../library/strings/suffix_array/suffix_array.hpp:62
knownConditionTrueFalse:../library/strings/suffix_array/suffix_array_short.hpp:34
knownConditionTrueFalse:../library/dsu/kruskal_tree.hpp:15
knownConditionTrueFalse:../library/dsu/kruskal_tree.hpp:13
knownConditionTrueFalse:../library/dsu/dsu.hpp:11
constVariable:../kactl/content/numerical/NumberTheoreticTransform.h:30
constVariable:../kactl/content/graph/CompressTree.h:20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ int main() {
dsu.join(u, v);
adj[u].push_back(v);
adj[v].push_back(u);
} else cout << dsu.same_set(u, v) << '\n';
if (rnd<int>(0, 20'000) == 0) check();
} else cout << (dsu.f(u) == dsu.f(v)) << '\n';
if (i <= 20 || rnd<int>(0, 20'000) == 0) check();
}
check();
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ int main() {
int mst_sum = 0;
vector<int> edge_weights;
vector<int> to_time(n);
for (int v = lt.find(0), timer = 1;
for (int v = lt.f(0), timer = 1;
lt.edge[v] != pii{-1, -1};
v = lt.edge[v].first, timer++) {
edge_weights.push_back(w_eds[lt.edge[v].second][0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ int main() {
assert(lt.size(0) == n);
int64_t cost = 0;
vector<int> ids;
for (int v = lt.find(0); lt.edge[v].first != -1;
for (int v = lt.f(0); lt.edge[v].first != -1;
v = lt.edge[v].first) {
ids.push_back(w_eds[lt.edge[v].second][0]);
cost += weights[w_eds[lt.edge[v].second][0]];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,31 @@ int main() {
cin.tie(0)->sync_with_stdio(0);
int n, q;
cin >> n >> q;
rp_dsu dsu(n);
rp_dsu r_dsu(n);
vi y(n);
for (int i = 0; i < n; i++) cin >> y[i];
vi x = y;
int ans = 0;
DSU dsu(n);
auto f = [&](int u, int v) {
ans = (ans + 1LL * x[u] * x[v]) % mod;
x[u] = (x[u] + x[v]) % mod;
u = dsu.f(u);
v = dsu.f(v);
assert(dsu.join(u, v));
int root = dsu.f(u);
int other = root ^ u ^ v;
ans = (ans + 1LL * x[root] * x[other]) % mod;
x[root] = (x[root] + x[other]) % mod;
};
vector<array<int, 3>> queries;
queries.reserve(q);
vector<vector<pii>> joins(n + 1);
for (int qq = 0; qq < q; qq++) {
int k, a, b;
cin >> k >> a >> b;
dsu.join(a, b, k, f);
queries.push_back({a, b, k});
if (k) r_dsu.join(a, b, k, f);
joins[k].emplace_back(a, b);
cout << ans << '\n';
if (qq == 0 || qq == 1 || qq == 10 || qq == 1000 ||
qq == 100'000 || qq == q - 1) {
auto uf = get_rp_dsu(queries, n);
auto uf = get_rp_dsu(joins, n);
vi sums(n);
int offline_ans = 0;
for (int i = 0; i < n; i++) {
Expand Down
2 changes: 1 addition & 1 deletion tests/scripts/compile_commented_snippets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ git submodule update
echo "vi rhs;"
echo "vector<vi> mat;"
echo "vector<vector<bool>> grid;"
echo "int n,m,k,tl,tr,l,r,l1,r1,l2,r2,s_l,s_r,root_l,root_r,source,sink,total_flow,bccid,u,v,lsz,rsz,cols,cap,num,x,y,i,j,i1,i2,j1,j2;"
echo "int n,m,k,tl,tr,l,r,l1,r1,l2,r2,s_l,s_r,root_l,root_r,source,sink,total_flow,bccid,u,v,lsz,rsz,cols,cap,num,x,y,i,j,i1,i2,j1,j2,len;"
} >entire_library_without_main

{
Expand Down
Loading