Skip to content

Block-Cut Tree

Code

Block-Cut Tree
// Block-Cut Tree {{{
struct BlockCutTree {
  int N;
  vector<vector<int>> const& G;

  stack<pair<int, int>> S;
  int TIMER = -1;
  vector<int> pre, low;

  vector<int> art;
  vector<bool> is_art;
  vector<vector<pair<int, int>>> bcc;

  vector<vector<int>> BCT;
  vector<int> comp;

  void make_bcc(pair<int, int> until) {
    bcc.push_back({});
    pair<int, int> e{-1, -1};
    while (e != until) {
      e = S.top(); S.pop();
      bcc.back().push_back(e);
    }
  }

  void dfs(int v, int p) {
    pre[v] = low[v] = ++TIMER;

    int children = 0;
    bool low_child = false;

    for (auto u : G[v]) {
      if (u == p) continue;
      if (pre[u] == -1) {
        S.push({v, u});
        dfs(u, v);
        children++;

        low[v] = min(low[v], low[u]);
        if (low[u] >= pre[v]) {
          low_child = true;
          make_bcc({v, u});
        }
      } else {
        low[v] = min(low[v], pre[u]);
      }
    }

    if ((p == -1 && children >= 2) || (p != -1 && low_child))
      art.push_back(v);
  }


  BlockCutTree(vector<vector<int>> const& G) : G(G), N(size(G)) {
    pre.assign(N, -1);
    low.assign(N, -1);
    for (int i = 0; i < N; i++) {
      if (pre[i] == -1) {
        dfs(i, -1);
      }
    }

    is_art.resize(N, false);
    for (auto v : art) is_art[v] = true;

    BCT.resize(N + size(bcc));
    comp.resize(N);
    for (int i = 0; i < size(bcc); i++) {
      for (auto [v, u] : bcc[i]) {
        if (is_art[v] && (empty(BCT[v]) || BCT[v].back() != N+i)) BCT[v].push_back(N+i), BCT[N+i].push_back(v);
        if (is_art[u] && (empty(BCT[u]) || BCT[u].back() != N+i)) BCT[u].push_back(N+i), BCT[N+i].push_back(u);
        comp[v] = comp[u] = N+i;
      }
    }

    for (auto v : art) comp[v] = v;
  }
};
//}}}