Skip to content

block_cut_tree.hpp

SECTIONGraph INCLUDEnoya/block_cut_tree.hpp

把无向图的点双连通分量与割点组织成圆方树;便于将经过割点的路径问题转成树问题。

Complexity: Time: O(V + E). Space: O(V + E).

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: O(V + E).
/// Space: O(V + E).

#include "noya/lowlink.hpp"

#include <cassert>
#include <utility>
#include <vector>

namespace noya {

/// @brief Block-cut incidence forest of an undirected multigraph. Original
/// vertices use ids [0, n), and block nodes use ids [n, n + blk.size()).
struct block_cut_forest {
  int n = 0;
  std::vector<std::vector<int>> blk;
  std::vector<std::vector<int>> tr;
  std::vector<std::vector<int>> bel;

  block_cut_forest() = default;
  block_cut_forest(int n_, const std::vector<std::pair<int, int>> &es) {
    build(n_, es);
  }
  explicit block_cut_forest(const lowlink &dec) {
    build(dec);
  }

  /// @brief Rebuild the forest from an edge list.
  void build(int n_, const std::vector<std::pair<int, int>> &es) {
    build(lowlink(n_, es));
  }

  /// @brief Rebuild the forest from an existing lowlink dec.
  void build(const lowlink &dec) {
    n = dec.n;
    blk = dec.bcc;
    tr.assign(n + blk.size(), {});
    bel.assign(n, {});
    for (int bid = 0; bid < int(blk.size()); bid++) {
      int nd = block_node(bid);
      for (int u : blk[bid]) {
        assert(0 <= u && u < n);
        tr[u].push_back(nd);
        tr[nd].push_back(u);
        bel[u].push_back(bid);
      }
    }
  }

  int block_node(int bid) const {
    assert(0 <= bid && bid < int(blk.size()));
    return n + bid;
  }

  bool is_block_node(int nd) const {
    assert(0 <= nd && nd < int(tr.size()));
    return nd >= n;
  }
};

} // namespace noya
#ifndef NOYA_BLOCK_CUT_TREE_HPP
#define NOYA_BLOCK_CUT_TREE_HPP 1

/// @complexity Time: O(V + E).
/// Space: O(V + E).

#include "noya/lowlink.hpp"

#include <cassert>
#include <utility>
#include <vector>

namespace noya {

/// @brief Block-cut incidence forest of an undirected multigraph. Original
/// vertices use ids [0, n), and block nodes use ids [n, n + blk.size()).
struct block_cut_forest {
  int n = 0;
  std::vector<std::vector<int>> blk;
  std::vector<std::vector<int>> tr;
  std::vector<std::vector<int>> bel;

  block_cut_forest() = default;
  block_cut_forest(int n_, const std::vector<std::pair<int, int>> &es) {
    build(n_, es);
  }
  explicit block_cut_forest(const lowlink &dec) {
    build(dec);
  }

  /// @brief Rebuild the forest from an edge list.
  void build(int n_, const std::vector<std::pair<int, int>> &es) {
    build(lowlink(n_, es));
  }

  /// @brief Rebuild the forest from an existing lowlink dec.
  void build(const lowlink &dec) {
    n = dec.n;
    blk = dec.bcc;
    tr.assign(n + blk.size(), {});
    bel.assign(n, {});
    for (int bid = 0; bid < int(blk.size()); bid++) {
      int nd = block_node(bid);
      for (int u : blk[bid]) {
        assert(0 <= u && u < n);
        tr[u].push_back(nd);
        tr[nd].push_back(u);
        bel[u].push_back(bid);
      }
    }
  }

  int block_node(int bid) const {
    assert(0 <= bid && bid < int(blk.size()));
    return n + bid;
  }

  bool is_block_node(int nd) const {
    assert(0 <= nd && nd < int(tr.size()));
    return nd >= n;
  }
};

} // namespace noya

#endif // NOYA_BLOCK_CUT_TREE_HPP
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>

/// @complexity Time: O(V + E).
/// Space: O(V + E).

/// @complexity Time: O(V + E).
/// Space: O(V + E).

namespace noya {

/// @brief Lowlink decomposition of an undirected multigraph.
struct lowlink {
  int n = 0;
  std::vector<std::pair<int, int>> es;
  std::vector<std::vector<std::pair<int, int>>> g;
  std::vector<int> ord;
  std::vector<int> low;
  std::vector<bool> cut;
  std::vector<int> bri;
  std::vector<std::vector<int>> bcc;
  std::vector<int> ecc;
  int cnt = 0;

  lowlink() = default;
  lowlink(int n_, const std::vector<std::pair<int, int>> &es_) {
    build(n_, es_);
  }

  /// @brief Rebuild cut points, bridges, vertex-biconnected
  /// components, and two-edge-connected components.
  void build(int n_, const std::vector<std::pair<int, int>> &es_) {
    assert(n_ >= 0);
    n = n_;
    es = es_;
    g.assign(n, {});
    for (int id = 0; id < int(es.size()); id++) {
      auto [u, v] = es[id];
      assert(0 <= u && u < n);
      assert(0 <= v && v < n);
      g[u].emplace_back(v, id);
      g[v].emplace_back(u, id);
    }

    ord.assign(n, -1);
    low.assign(n, -1);
    cut.assign(n, false);
    bri.clear();
    bcc.clear();
    tim = 0;
    es1.clear();
    for (int rt = 0; rt < n; rt++) {
      if (ord[rt] == -1) {
        dfs(rt, -1, rt);
        if (g[rt].empty()) {
          bcc.push_back({rt});
        }
      }
    }
    for (auto [u, v] : es) {
      if (u == v) {
        bcc.push_back({u});
      }
    }
    std::sort(bri.begin(), bri.end());
    build_two_edge_components();
  }

  /// @brief Return whether an input edge is a bridge.
  bool is_bridge(int eid) const {
    assert(0 <= eid && eid < int(es.size()));
    return std::binary_search(bri.begin(), bri.end(), eid);
  }

private:
  int tim = 0;
  std::vector<int> es1;

  void dfs(int u, int pe, int rt) {
    ord[u] = low[u] = tim++;
    int num = 0;
    for (auto [v, eid] : g[u]) {
      if (eid == pe || u == v) {
        continue;
      }
      if (ord[v] == -1) {
        num++;
        es1.push_back(eid);
        dfs(v, eid, rt);
        low[u] = std::min(low[u], low[v]);
        if (low[v] > ord[u]) {
          bri.push_back(eid);
        }
        if (low[v] >= ord[u]) {
          if (u != rt || num >= 2) {
            cut[u] = true;
          }
          std::vector<int> vs;
          while (true) {
            int id = es1.back();
            es1.pop_back();
            vs.push_back(es[id].first);
            vs.push_back(es[id].second);
            if (id == eid) {
              break;
            }
          }
          std::sort(vs.begin(), vs.end());
          vs.erase(std::unique(vs.begin(), vs.end()), vs.end());
          bcc.push_back(std::move(vs));
        }
      } else if (ord[v] < ord[u]) {
        es1.push_back(eid);
        low[u] = std::min(low[u], ord[v]);
      }
    }
  }

  void build_two_edge_components() {
    std::vector<bool> br1(es.size());
    for (int id : bri) {
      br1[id] = true;
    }
    ecc.assign(n, -1);
    cnt = 0;
    std::vector<int> stk;
    for (int s = 0; s < n; s++) {
      if (ecc[s] != -1) {
        continue;
      }
      ecc[s] = cnt;
      stk.push_back(s);
      while (!stk.empty()) {
        int u = stk.back();
        stk.pop_back();
        for (auto [v, eid] : g[u]) {
          if (!br1[eid] && ecc[v] == -1) {
            ecc[v] = cnt;
            stk.push_back(v);
          }
        }
      }
      cnt++;
    }
  }
};

} // namespace noya

namespace noya {

/// @brief Block-cut incidence forest of an undirected multigraph. Original
/// vertices use ids [0, n), and block nodes use ids [n, n + blk.size()).
struct block_cut_forest {
  int n = 0;
  std::vector<std::vector<int>> blk;
  std::vector<std::vector<int>> tr;
  std::vector<std::vector<int>> bel;

  block_cut_forest() = default;
  block_cut_forest(int n_, const std::vector<std::pair<int, int>> &es) {
    build(n_, es);
  }
  explicit block_cut_forest(const lowlink &dec) {
    build(dec);
  }

  /// @brief Rebuild the forest from an edge list.
  void build(int n_, const std::vector<std::pair<int, int>> &es) {
    build(lowlink(n_, es));
  }

  /// @brief Rebuild the forest from an existing lowlink dec.
  void build(const lowlink &dec) {
    n = dec.n;
    blk = dec.bcc;
    tr.assign(n + blk.size(), {});
    bel.assign(n, {});
    for (int bid = 0; bid < int(blk.size()); bid++) {
      int nd = block_node(bid);
      for (int u : blk[bid]) {
        assert(0 <= u && u < n);
        tr[u].push_back(nd);
        tr[nd].push_back(u);
        bel[u].push_back(bid);
      }
    }
  }

  int block_node(int bid) const {
    assert(0 <= bid && bid < int(blk.size()));
    return n + bid;
  }

  bool is_block_node(int nd) const {
    assert(0 <= nd && nd < int(tr.size()));
    return nd >= n;
  }
};

} // namespace noya