C++ アルゴリズムとデータ構造のライブラリ
#include "library/graph/tree/centroid_decomposition.hpp"int N, M;
CentroidDecomposition cd(N);
cd.read(M); // グラフ構造体と同様に作成
// 重心分解を実行。戻り値は重心分解ツリー全体の根
int root = cd.build();
// cd.tree に重心分解後の親子関係が格納される
// ex) cd.tree.g[u] には、重心分解ツリーにおける u の子リストが入る
#pragma once
#include "library/graph/base/graph.hpp"
struct CentroidDecomposition : Graph {
public:
using Graph::G;
using Graph::Graph;
Graph tree;
int build() {
sub.assign(G.size(), 0ll);
v.assign(G.size(), 0ll);
tree = Graph(G.size());
return build_dfs(0ll);
}
explicit CentroidDecomposition(const Graph &G) : Graph(G) {}
private:
vector<int> sub;
vector<int> v;
inline int build_dfs(int idx, int par) {
sub[idx] = 1;
for (auto &&edge : G[idx]) {
if (edge.to == par or v[edge.to]) continue;
sub[idx] += build_dfs(edge.to, idx);
}
return sub[idx];
}
inline int search_centroid(int idx, int par, const int mid) {
for (auto &&edge : G[idx]) {
if (edge.to == par or v[edge.to]) continue;
if (sub[edge.to] > mid) return search_centroid(edge.to, idx, mid);
}
return idx;
}
inline int build_dfs(int idx) {
int centroid = search_centroid(idx, -1, build_dfs(idx, -1) / 2ll);
v[centroid] = true;
for (auto &&edge : G[centroid]) {
if (!v[edge.to]) tree.add(centroid, build_dfs(edge.to));
}
v[centroid] = false;
return centroid;
}
};#line 2 "library/graph/base/edge.hpp"
struct Edge {
int from, to;
long long cost;
int idx;
Edge(int from, int to, long long cost = 1, int idx = -1)
: from(from), to(to), cost(cost), idx(idx) {}
};
#line 3 "library/graph/base/graph.hpp"
struct Graph {
int N;
vector<vector<Edge>> G;
int es;
Graph() = default;
Graph(int N) : N(N), G(N), es(0) {}
const vector<Edge> &operator[](int v) const { return G[v]; }
int size() const { return N; }
void add(int from, int to, long long cost = 1) {
G[from].push_back(Edge(from, to, cost, es++));
}
void add_both(int from, int to, long long cost = 1) {
G[from].push_back(Edge(from, to, cost, es));
G[to].push_back(Edge(to, from, cost, es++));
}
void read(int M, int padding = -1, bool weighted = false,
bool directed = false) {
for (int i = 0; i < M; i++) {
int u, v;
cin >> u >> v;
u += padding, v += padding;
long long cost = 1ll;
if (weighted) cin >> cost;
if (directed) {
add(u, v, cost);
} else {
add_both(u, v, cost);
}
}
}
};
#line 3 "library/graph/tree/centroid_decomposition.hpp"
struct CentroidDecomposition : Graph {
public:
using Graph::G;
using Graph::Graph;
Graph tree;
int build() {
sub.assign(G.size(), 0ll);
v.assign(G.size(), 0ll);
tree = Graph(G.size());
return build_dfs(0ll);
}
explicit CentroidDecomposition(const Graph &G) : Graph(G) {}
private:
vector<int> sub;
vector<int> v;
inline int build_dfs(int idx, int par) {
sub[idx] = 1;
for (auto &&edge : G[idx]) {
if (edge.to == par or v[edge.to]) continue;
sub[idx] += build_dfs(edge.to, idx);
}
return sub[idx];
}
inline int search_centroid(int idx, int par, const int mid) {
for (auto &&edge : G[idx]) {
if (edge.to == par or v[edge.to]) continue;
if (sub[edge.to] > mid) return search_centroid(edge.to, idx, mid);
}
return idx;
}
inline int build_dfs(int idx) {
int centroid = search_centroid(idx, -1, build_dfs(idx, -1) / 2ll);
v[centroid] = true;
for (auto &&edge : G[centroid]) {
if (!v[edge.to]) tree.add(centroid, build_dfs(edge.to));
}
v[centroid] = false;
return centroid;
}
};