Skip to content

centroid_decomposition.hpp

SECTIONGraph INCLUDEnoya/centroid_decomposition.hpp

Centroid-decomposition tree of an undirected tree.

构造树的点分治层次;适合按距离维护全局动态点集、统计经过重心的路径。

Implementation

View on GitHub

#ifndef NOYA_CENTROID_DECOMPOSITION_HPP
#define NOYA_CENTROID_DECOMPOSITION_HPP 1

/// @complexity Time: O(n log n).
/// Space: O(n).

#include <cassert>
#include <vector>

namespace noya {

/// @brief Centroid-decomposition tree of an undirected tree.
struct centroid_decomposition {
  int n = 0;
  int root = -1;
  std::vector<int> parent;
  std::vector<int> level;
  std::vector<int> order;

  centroid_decomposition() = default;
  explicit centroid_decomposition(const std::vector<std::vector<int>> &graph) {
    build(graph);
  }

  /// @brief Rebuild the centroid tree; parent[root] is -1 and order is the
  /// decomposition order.
  void build(const std::vector<std::vector<int>> &graph) {
    n = int(graph.size());
    parent.assign(n, -1);
    level.assign(n, -1);
    order.clear();
    if (n == 0) {
      root = -1;
      return;
    }
    std::vector<int> subtree_size(n);
    std::vector<bool> removed(n);

    auto compute_size = [&](auto &self, int vertex, int previous) -> int {
      subtree_size[vertex] = 1;
      for (int next : graph[vertex]) {
        if (next != previous && !removed[next]) {
          subtree_size[vertex] += self(self, next, vertex);
        }
      }
      return subtree_size[vertex];
    };
    auto find_centroid = [&](auto &self, int vertex, int previous,
                             int total) -> int {
      for (int next : graph[vertex]) {
        if (next != previous && !removed[next] &&
            subtree_size[next] > total / 2) {
          return self(self, next, vertex, total);
        }
      }
      return vertex;
    };
    auto decompose = [&](auto &self, int entry, int centroid_parent,
                         int centroid_level) -> int {
      int total = compute_size(compute_size, entry, -1);
      int centroid = find_centroid(find_centroid, entry, -1, total);
      parent[centroid] = centroid_parent;
      level[centroid] = centroid_level;
      order.push_back(centroid);
      removed[centroid] = true;
      for (int next : graph[centroid]) {
        if (!removed[next]) {
          self(self, next, centroid, centroid_level + 1);
        }
      }
      return centroid;
    };
    root = decompose(decompose, 0, -1, 0);
  }
};

} // namespace noya

#endif // NOYA_CENTROID_DECOMPOSITION_HPP
#include <cassert>
#include <vector>

/// @complexity Time: O(n log n).
/// Space: O(n).

namespace noya {

/// @brief Centroid-decomposition tree of an undirected tree.
struct centroid_decomposition {
  int n = 0;
  int root = -1;
  std::vector<int> parent;
  std::vector<int> level;
  std::vector<int> order;

  centroid_decomposition() = default;
  explicit centroid_decomposition(const std::vector<std::vector<int>> &graph) {
    build(graph);
  }

  /// @brief Rebuild the centroid tree; parent[root] is -1 and order is the
  /// decomposition order.
  void build(const std::vector<std::vector<int>> &graph) {
    n = int(graph.size());
    parent.assign(n, -1);
    level.assign(n, -1);
    order.clear();
    if (n == 0) {
      root = -1;
      return;
    }
    std::vector<int> subtree_size(n);
    std::vector<bool> removed(n);

    auto compute_size = [&](auto &self, int vertex, int previous) -> int {
      subtree_size[vertex] = 1;
      for (int next : graph[vertex]) {
        if (next != previous && !removed[next]) {
          subtree_size[vertex] += self(self, next, vertex);
        }
      }
      return subtree_size[vertex];
    };
    auto find_centroid = [&](auto &self, int vertex, int previous,
                             int total) -> int {
      for (int next : graph[vertex]) {
        if (next != previous && !removed[next] &&
            subtree_size[next] > total / 2) {
          return self(self, next, vertex, total);
        }
      }
      return vertex;
    };
    auto decompose = [&](auto &self, int entry, int centroid_parent,
                         int centroid_level) -> int {
      int total = compute_size(compute_size, entry, -1);
      int centroid = find_centroid(find_centroid, entry, -1, total);
      parent[centroid] = centroid_parent;
      level[centroid] = centroid_level;
      order.push_back(centroid);
      removed[centroid] = true;
      for (int next : graph[centroid]) {
        if (!removed[next]) {
          self(self, next, centroid, centroid_level + 1);
        }
      }
      return centroid;
    };
    root = decompose(decompose, 0, -1, 0);
  }
};

} // namespace noya