serna37's Library

Logo

C++ アルゴリズムとデータ構造のライブラリ

View the Project on GitHub serna37/library-cpp

:heavy_check_mark: 重心分解
(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 の子リストが入る

Depends on

Verified with

Code

#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;
    }
};
Back to top page