C++ Library for Competitive Programming
#include "emthrm/graph/tree/centroid_decomposition.hpp"
重心を基にした木の分解法の一つである。木上で分割統治法を行うときに有用である。
$O(\lvert V \rvert \log{\lvert V \rvert})$
template <typename CostType>
struct CentroidDecomposition;
CostType
:辺のコストを表す型名前 | 説明 |
---|---|
int root |
重心分解した木の根 |
std::vector<int> parent |
parent[i] は g における頂点 $i$ の親を表す。ただし存在しないときは $-1$ となる。 |
std::vector<std::vector<int>> g |
重心分解を行った木 |
名前 | 効果 |
---|---|
explicit CentroidDecomposition(const std::vector<std::vector<Edge<CostType>>>& graph); |
木 $\mathrm{graph}$ に対してオブジェクトを構築する。 |
https://atcoder.jp/contests/abc291/submissions/39252522
#ifndef EMTHRM_GRAPH_TREE_CENTROID_DECOMPOSITION_HPP_
#define EMTHRM_GRAPH_TREE_CENTROID_DECOMPOSITION_HPP_
#include <ranges>
#include <vector>
#include "emthrm/graph/edge.hpp"
namespace emthrm {
template <typename CostType>
struct CentroidDecomposition {
int root;
std::vector<int> parent;
std::vector<std::vector<int>> g;
explicit CentroidDecomposition(
const std::vector<std::vector<Edge<CostType>>>& graph)
: graph(graph) {
const int n = graph.size();
parent.assign(n, -1);
g.resize(n);
is_alive.assign(n, true);
subtree.resize(n);
root = build(0);
}
private:
std::vector<bool> is_alive;
std::vector<int> subtree;
const std::vector<std::vector<Edge<CostType>>> graph;
int build(const int s) {
const int centroid = search_centroid(-1, s, calc_subtree(-1, s) / 2);
is_alive[centroid] = false;
for (const int e : graph[centroid]
| std::views::transform(&Edge<CostType>::dst)) {
if (is_alive[e]) {
const int child = build(e);
g[centroid].emplace_back(child);
parent[child] = centroid;
}
}
is_alive[centroid] = true;
return centroid;
}
int calc_subtree(const int par, const int ver) {
subtree[ver] = 1;
for (const int e : graph[ver]
| std::views::transform(&Edge<CostType>::dst)) {
if (e != par && is_alive[e]) {
subtree[ver] += calc_subtree(ver, e);
}
}
return subtree[ver];
}
int search_centroid(const int par, const int ver, const int half) const {
for (const int e : graph[ver]
| std::views::transform(&Edge<CostType>::dst)) {
if (e != par && is_alive[e] && subtree[e] > half) {
return search_centroid(ver, e, half);
}
}
return ver;
}
};
} // namespace emthrm
#endif // EMTHRM_GRAPH_TREE_CENTROID_DECOMPOSITION_HPP_
#line 1 "include/emthrm/graph/tree/centroid_decomposition.hpp"
#include <ranges>
#include <vector>
#line 1 "include/emthrm/graph/edge.hpp"
/**
* @title 辺
*/
#ifndef EMTHRM_GRAPH_EDGE_HPP_
#define EMTHRM_GRAPH_EDGE_HPP_
#include <compare>
namespace emthrm {
template <typename CostType>
struct Edge {
CostType cost;
int src, dst;
explicit Edge(const int src, const int dst, const CostType cost = 0)
: cost(cost), src(src), dst(dst) {}
auto operator<=>(const Edge& x) const = default;
};
} // namespace emthrm
#endif // EMTHRM_GRAPH_EDGE_HPP_
#line 8 "include/emthrm/graph/tree/centroid_decomposition.hpp"
namespace emthrm {
template <typename CostType>
struct CentroidDecomposition {
int root;
std::vector<int> parent;
std::vector<std::vector<int>> g;
explicit CentroidDecomposition(
const std::vector<std::vector<Edge<CostType>>>& graph)
: graph(graph) {
const int n = graph.size();
parent.assign(n, -1);
g.resize(n);
is_alive.assign(n, true);
subtree.resize(n);
root = build(0);
}
private:
std::vector<bool> is_alive;
std::vector<int> subtree;
const std::vector<std::vector<Edge<CostType>>> graph;
int build(const int s) {
const int centroid = search_centroid(-1, s, calc_subtree(-1, s) / 2);
is_alive[centroid] = false;
for (const int e : graph[centroid]
| std::views::transform(&Edge<CostType>::dst)) {
if (is_alive[e]) {
const int child = build(e);
g[centroid].emplace_back(child);
parent[child] = centroid;
}
}
is_alive[centroid] = true;
return centroid;
}
int calc_subtree(const int par, const int ver) {
subtree[ver] = 1;
for (const int e : graph[ver]
| std::views::transform(&Edge<CostType>::dst)) {
if (e != par && is_alive[e]) {
subtree[ver] += calc_subtree(ver, e);
}
}
return subtree[ver];
}
int search_centroid(const int par, const int ver, const int half) const {
for (const int e : graph[ver]
| std::views::transform(&Edge<CostType>::dst)) {
if (e != par && is_alive[e] && subtree[e] > half) {
return search_centroid(ver, e, half);
}
}
return ver;
}
};
} // namespace emthrm