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
10 changes: 5 additions & 5 deletions .verify-helper/timestamps.remote.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp": "2025-02-10 23:30:47 -0700",
"tests/library_checker_aizu_tests/handmade_tests/count_paths_forest.test.cpp": "2024-12-15 14:34:10 -0600",
"tests/library_checker_aizu_tests/handmade_tests/dsu_size.test.cpp": "2024-12-14 19:50:29 -0600",
"tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2024-12-15 17:01:11 -0600",
"tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2025-04-22 19:30:56 -0600",
"tests/library_checker_aizu_tests/handmade_tests/fib_matrix_expo.test.cpp": "2024-12-14 19:50:29 -0600",
"tests/library_checker_aizu_tests/handmade_tests/functional_graph.test.cpp": "2025-02-10 23:30:47 -0700",
"tests/library_checker_aizu_tests/handmade_tests/lca_ladder_forest.test.cpp": "2025-02-10 23:30:47 -0700",
Expand Down Expand Up @@ -124,10 +124,10 @@
"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",
"tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2024-12-15 14:34:10 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp": "2024-12-15 17:01:11 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp": "2024-12-15 17:01:11 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp": "2024-12-15 17:01:11 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp": "2024-12-15 17:01:11 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp": "2025-04-22 19:30:56 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp": "2025-04-22 19:30:56 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp": "2025-04-22 19:30:56 -0600",
"tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp": "2025-04-22 19:30:56 -0600",
"tests/library_checker_aizu_tests/trees/kth_path_ladder.test.cpp": "2025-02-10 23:30:47 -0700",
"tests/library_checker_aizu_tests/trees/kth_path_linear.test.cpp": "2025-02-10 23:30:47 -0700",
"tests/library_checker_aizu_tests/trees/kth_path_tree_lift.test.cpp": "2025-02-10 14:50:36 -0700",
Expand Down
37 changes: 17 additions & 20 deletions library/trees/edge_cd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,41 @@
//! });
//! @endcode
//! handle single-edge-paths separately
//! @time O(n log1.5 n)
//! @time O(n logφ n)
//! @space O(n)
template<class F, class G> struct edge_cd {
vector<G> adj;
F f;
vi sub_sz;
vi siz;
edge_cd(const vector<G>& adj, F f):
adj(adj), f(f), sub_sz(sz(adj)) {
dfs(0, sz(adj));
adj(adj), f(f), siz(sz(adj)) {
dfs(0, sz(adj) - 1);
}
int find_cent(int v, int p, int siz) {
sub_sz[v] = 1;
int find_cent(int v, int p, int m) {
siz[v] = 1;
for (int u : adj[v])
if (u != p) {
int cent = find_cent(u, v, siz);
int cent = find_cent(u, v, m);
if (cent != -1) return cent;
sub_sz[v] += sub_sz[u];
siz[v] += siz[u];
}
if (p == -1) return v;
return 2 * sub_sz[v] >= siz
? sub_sz[p] = siz - sub_sz[v],
v : -1;
return 2 * siz[v] > m ? siz[p] = m + 1 - siz[v],
v : -1;
}
void dfs(int v, int siz) {
if (siz <= 2) return;
v = find_cent(v, -1, siz);
void dfs(int v, int m) {
if (m < 2) return;
v = find_cent(v, -1, m);
int sum = 0;
auto it = partition(all(adj[v]), [&](int u) {
bool ret = 2 * sum + sub_sz[u] < siz - 1 &&
3 * (sum + sub_sz[u]) <= 2 * (siz - 1);
if (ret) sum += sub_sz[u];
return ret;
ll x = sum + siz[u];
return x * x < m * (m - x) ? sum += siz[u], 1 : 0;
});
f(adj, v, it - begin(adj[v]));
G oth(it, end(adj[v]));
adj[v].erase(it, end(adj[v]));
dfs(v, sum + 1);
dfs(v, sum);
swap(adj[v], oth);
dfs(v, siz - sum);
dfs(v, m - sum);
}
};
36 changes: 0 additions & 36 deletions library/trees/edge_centroid_decomp_uncommon/README.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include "../../data_structures/bit.hpp"
#include "sum_adjacent.hpp"
#include "../edge_cd.hpp"
#include "sum_adjacent.hpp"
//! https://judge.yosupo.jp/problem/vertex_add_range_contour_sum_on_tree
struct contour_range_query {
int n;
Expand All @@ -10,8 +10,8 @@ struct contour_range_query {
vector<array<BIT, 2>> bits;
//! @param adj unrooted, undirected tree
//! @param a a[v] = initial number for node v
//! @time O(n log1.5 n)
//! @space O(n log1.5 n) for `info` and `bits`
//! @time O(n logφ n)
//! @space O(n logφ n) for `info` and `bits`
contour_range_query(const vector<vi>& adj,
const vector<ll>& a):
n(sz(a)), sum_a(adj, a), info(n) {
Expand All @@ -34,7 +34,7 @@ struct contour_range_query {
}
//! @param v node
//! @param delta number to add to node v's number
//! @time O(log1.5(n) * log2(n))
//! @time O(logφ(n) * log2(n))
//! @space O(1)
void update(int v, ll delta) {
sum_a.update(v, delta);
Expand All @@ -46,7 +46,7 @@ struct contour_range_query {
//! @returns sum of node u's number over all u such that
//! l
//! <= dist_edges(u, v) < r
//! @time O(log1.5(n) * log2(n))
//! @time O(logφ(n) * log2(n))
//! @space O(1)
ll query(int v, int l, int r) {
ll sum = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include "../../data_structures/bit_uncommon/rupq.hpp"
#include "sum_adjacent.hpp"
#include "../edge_cd.hpp"
#include "sum_adjacent.hpp"
//! https://judge.yosupo.jp/problem/vertex_get_range_contour_add_on_tree
struct contour_range_update {
int n;
Expand All @@ -11,8 +11,8 @@ struct contour_range_update {
vector<array<bit_rupq, 2>> bits;
//! @param adj unrooted, undirected tree
//! @param a a[v] = initial number for node v
//! @time O(n log1.5 n)
//! @space O(n log1.5 n) for `info` and `bits`
//! @time O(n logφ n)
//! @space O(n logφ n) for `info` and `bits`
contour_range_update(const vector<vi>& adj,
const vector<ll>& a):
n(sz(a)), a(a), sum_a(adj, vector<ll>(n)), info(n) {
Expand All @@ -34,7 +34,7 @@ struct contour_range_update {
}
//! @param v,l,r,delta add delta to all nodes u such
//! that l <= dist_edges(v, u) < r
//! @time O(log1.5(n) * log2(n))
//! @time O(logφ(n) * log2(n))
//! @space O(1)
void update(int v, int l, int r, ll delta) {
if (l <= 0 && 0 < r) a[v] += delta;
Expand All @@ -48,7 +48,7 @@ struct contour_range_update {
}
//! @param v node
//! @returns number of node v
//! @time O(log1.5(n) * log2(n))
//! @time O(logφ(n) * log2(n))
//! @space O(1)
ll query(int v) {
ll sum = a[v] + sum_a.query(v);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! @param adj unrooted, connected tree
//! @returns array `num_paths` where `num_paths[i]` = # of
//! paths in tree with `i` edges. `num_paths[1]` = # edges
//! @time O(n * log1.5(n) * log2(n))
//! @time O(n * logφ(n) * log2(n))
//! @space this function allocates/returns various vectors
//! which are each O(n)
vector<ll> count_paths_per_length(const vector<vi>& adj) {
Expand Down
28 changes: 26 additions & 2 deletions tests/library_checker_aizu_tests/edge_cd_asserts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,36 @@ void edge_cd_asserts(const vector<vi>& adj, int cent,
int sz_all = dfs(dfs, cent, -1);
assert(sz_all >= 3);
array<int, 2> cnts = {0, 0};
array<int, 2> max_cnt = {0, 0};
for (int i = 0; i < sz(adj[cent]); i++) {
int sz_subtree = dfs(dfs, adj[cent][i], cent);
assert(2 * sz_subtree <= sz_all);
cnts[i < split] += sz_subtree;
max_cnt[i < split] =
max(max_cnt[i < split], sz_subtree);
}
assert(cnts[0] + cnts[1] + 1 == sz_all);
for (int i = 0; i < 2; i++)
assert(0 < cnts[i] && cnts[i] <= 2 * cnts[!i]);
if (sz_all == 4) return;
// a is the number of edges in the smaller edge set
// b is the number of edges in the larger edge set
// so we know 1/2 <= b/(a+b)
// returns true iff b/(a+b) <= 1/phi
auto is_balanced = [&](ll a, ll b) -> bool {
assert(a <= b);
return b * b <= a * (a + b);
};
if (cnts[0] > cnts[1]) {
swap(cnts[0], cnts[1]);
swap(max_cnt[0], max_cnt[1]);
}
if (!is_balanced(cnts[0], cnts[1])) {
int a = max_cnt[1];
int b = cnts[1] - max_cnt[1];
assert(a > 0);
assert(b > 0);
if (a > b) swap(a, b);
assert(is_balanced(a, b));
assert(!is_balanced(a, cnts[0] + b));
assert(!is_balanced(b, cnts[0] + a));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/ITP1_1_A"
#define PROBLEM \
"https://onlinejudge.u-aizu.ac.jp/problems/ITP1_1_A"
#include "../template.hpp"
#include "../../../library/contest/random.hpp"
#include "../../../library/graphs/functional_graph_processor.hpp"
Expand All @@ -8,7 +9,7 @@ struct functional_graph_processor {
init(sz(next));
build(next);
}
template <class Graph_t>
template<class Graph_t>
functional_graph_processor(const Graph_t &g) {
init(g.n);
build(g);
Expand Down Expand Up @@ -100,31 +101,30 @@ struct functional_graph_processor {
}
int n;
vector<vector<int>> cycle;
vector<int> cycle_id; // id of the cycle it belongs to,
// -1 if not part of one
vector<int> cycle_pos; // position in its cycle, -1 if
// not part of one
vector<int> cycle_prev; // previous vertex in its cycle,
// -1 if not part of one
vector<int> component_size; // size of its weakly
// connected component
vector<int> root_of; // first reachable node in a cycle
vector<int> depth; // distance to its root
vector<vector<int>> abr; // forest of arborescences of reversed edges not
// on the cycles
vector<int> order; // dfs order of abr
vector<int> pos; // pos in the dfs order
vector<int> end; // [pos[u], end[u]) denotes the subtree
vector<int> size; // size of the subtree in abr
vector<int> cycle_id; // id of the cycle it belongs to,
// -1 if not part of one
vector<int> cycle_pos; // position in its cycle, -1 if
// not part of one
vector<int> cycle_prev; // previous vertex in its cycle,
// -1 if not part of one
vector<int> component_size; // size of its weakly
// connected component
vector<int> root_of; // first reachable node in a cycle
vector<int> depth; // distance to its root
vector<vector<int>>
abr; // forest of arborescences of reversed edges not
// on the cycles
vector<int> order; // dfs order of abr
vector<int> pos; // pos in the dfs order
vector<int> end; // [pos[u], end[u]) denotes the subtree
vector<int> size; // size of the subtree in abr
};

bool equal(const basic_string<int> &a, const vi &b) {
if (sz(a) != sz(b)) return 0;
for (int i = 0; i < sz(a); i++)
if (a[i] != b[i]) return 0;
return 1;
}

int main() {
cin.tie(0)->sync_with_stdio(0);
for (int num_tests = 100; num_tests--;) {
Expand All @@ -135,19 +135,23 @@ int main() {
functional_graph_processor fgp(a);
assert(cycle == fgp.cycle);
for (int i = 0; i < n; i++) {
int root = cycle[t[i].root_of.first][t[i].root_of.second];
int root =
cycle[t[i].root_of.first][t[i].root_of.second];
assert(root == fgp.root_of[i]);
assert(equal(t[i].childs, fgp.abr[i]));
assert((root == i) == (fgp.cycle_id[i] != -1));
if (root == i) {
assert(t[i].root_of.first == fgp.cycle_id[i]);
assert(t[i].root_of.second == fgp.cycle_pos[i]);
int cyc_len = ssize(cycle[t[i].root_of.first]);
assert(cycle[t[i].root_of.first][(t[i].root_of.second + 1) % cyc_len] ==
a[i]);
assert(
cycle[t[i].root_of.first]
[(t[i].root_of.second + 1) % cyc_len] ==
a[i]);
assert(fgp.cycle_prev[i] ==
cycle[t[i].root_of.first]
[(t[i].root_of.second - 1 + cyc_len) % cyc_len]);
cycle[t[i].root_of.first]
[(t[i].root_of.second - 1 + cyc_len) %
cyc_len]);
} else {
assert(fgp.cycle_prev[i] == -1);
}
Expand Down
3 changes: 2 additions & 1 deletion tests/library_checker_aizu_tests/math/xor_basis.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ int main() {
int64_t val2 = unordered.shrink(val1);
assert(val1 == val2);
for (int64_t v : unordered.b)
assert((bit_floor((unsigned long long)v) & val2) == 0);
assert(
(bit_floor((unsigned long long)v) & val2) == 0);
bool inserted_unordered = unordered.insert(elem);
bool inserted_ordered_ll = ordered_ll.insert(elem);
bool inserted_ordered_bitset =
Expand Down
1 change: 0 additions & 1 deletion tests/scripts/ptc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ rm ../library/monotonic_stack/mono_stack_ri.png || exit 1
rm ../library/strings/manacher/longest_palindrome_query.hpp || exit 1
rm ../library/trees/centroid_decomp_uncommon/count_paths_per_length.hpp || exit 1
rm ../library/trees/centroid_decomp_uncommon/count_paths_per_node.hpp || exit 1
rm ../library/trees/edge_centroid_decomp_uncommon/README.md || exit 1
rm ../library/trees/edge_centroid_decomp_uncommon/contour_range_query.hpp || exit 1
rm ../library/trees/edge_centroid_decomp_uncommon/contour_range_update.hpp || exit 1
rm ../library/trees/edge_centroid_decomp_uncommon/count_paths_per_length.hpp || exit 1
Expand Down
Loading