Nyaan's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View on GitHub

:heavy_check_mark: Functional Graph(なもりグラフ)の分解
(graph/funtional-graph.hpp)

Functional Graph(なもりグラフ)

頂点数$n$のなもりグラフを$\mathrm{O}(n\alpha (n))$で分解するライブラリ。

使い方

メンバ関数
メンバ変数

Depends on

Verified with

Code

#pragma once

#include <vector>

#include "../data-structure/union-find.hpp"
#include "../tree/heavy-light-decomposition.hpp"
#include "graph-template.hpp"

using namespace std;

template <typename T>
struct Namori {
  using G = WeightedGraph<T>;

  int n;
  G g;

  // 部分グラフ
  vector<G> aux;

  // ループ部分の(頂点,辺の重み)
  // loop[i].se は loop[i] と loop[i+1] の間の辺
  vector<pair<int, T>> loop;

  // 頂点の対応関係
  vector<pair<int, int>> mp;

  // HL分解
  vector<HeavyLightDecomposition<G>> hld;

  Namori(int _n = 0) : _uf(_n) { init(_n); }

  void init(int _n) {
    n = _n;
    g.resize(n);
    _uf.data.resize(n);
    fill(begin(_uf.data), end(_uf.data), -1);
    _is_loop.resize(n, false);
    mp.resize(n, make_pair(-1, -1));
  }

  void add_edge(int u, int v, T w = 1) {
    assert(_built == false);
    if (_uf.same(u, v)) {
      _root = u, _adj = v, _w = w;
    } else {
      _uf.unite(u, v);
      g[u].emplace_back(u, v, w);
      g[v].emplace_back(v, u, w);
    }
    if (++_es == n) build();
  }

  void build() {
    if (_built) return;

    _buf.resize(n, -1);
    dfs1(_root, -1);

    for (int c = _adj; c >= 0; c = _buf[c]) {
      loop.emplace_back(c, -1);
      _is_loop[c] = true;
      for (auto& e : g[c]) {
        if (e == _buf[c]) loop.back().second = e.cost;
      }
    }
    assert(loop.back().first == _root);
    loop.back().second = _w;

    _h.resize(n);
    for (auto& [i, _] : loop) dfs2(i, -1);

    fill(begin(_buf), end(_buf), 0);
    for (auto& [i, _] : loop) dfs3(i);

    _uf.data.clear();
    _buf.clear();
    _is_loop.clear();

    aux.resize(loop.size());
    for (int i = 0; i < (int)loop.size(); i++) {
      int k = loop[i].first, j = 0;
      dfs4(k, i, j);
      aux[i].resize(j);

      dfs5(k);
      hld.emplace_back(aux[i]);
    }

    _h.clear();
    _built = true;
  }

  pair<int, int> idx(int i) const { return mp[i]; }

  int root(int i) const { return loop[mp[i].first].first; }

 private:
  // 初期化用の状態変数
  UnionFind _uf;
  vector<int> _buf;
  vector<bool> _is_loop;
  int _root = -1, _adj = -1, _es = 0;
  bool _built = false;
  T _w = 0;
  G _h;

  // parをメモする
  void dfs1(int c, int p) {
    for (auto& d : g[c]) {
      if (d != p) {
        _buf[d] = c;
        dfs1(d, c);
      }
    }
  }

  // _h で有向木を作る
  void dfs2(int c, int p) {
    for (auto& d : g[c]) {
      if (d == p or _is_loop[d]) continue;
      _h[c].emplace_back(c, d, d.cost);
      dfs2(d, c);
    }
  }

  // HLD用に順番替え
  void dfs3(int c) {
    _buf[c] = 1;
    for (auto& d : _h[c]) {
      dfs3(d);
      _buf[c] += _buf[d];
      if (_buf[d] > _buf[_h[c][0]]) {
        swap(_h[c][0], d);
      }
    }
  }

  // 順番をつける
  void dfs4(int c, int i, int& j) {
    mp[c] = make_pair(i, j++);
    for (auto& d : _h[c]) {
      dfs4(d, i, j);
    }
  }

  // 部分グラフを作る
  void dfs5(int c) {
    for (auto& d : _h[c]) {
      dfs5(d);
      auto [i, j] = mp[c];
      auto [_, k] = mp[d];
      aux[i][j].emplace_back(j, k, d.cost);
      // 逆辺も入れたいときはここをオンにする(動くか不明)
      // aux[i][k].emplace_back(k, j, d.cost);
    }
  }
};

/**
 * @brief Functional Graph(なもりグラフ)の分解
 * @docs docs/graph/functional-graph.md
 */
#line 2 "graph/funtional-graph.hpp"

#include <vector>

#line 2 "data-structure/union-find.hpp"

struct UnionFind {
  vector<int> data;
  UnionFind(int N) : data(N, -1) {}

  int find(int k) { return data[k] < 0 ? k : data[k] = find(data[k]); }

  int unite(int x, int y) {
    if ((x = find(x)) == (y = find(y))) return false;
    if (data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return true;
  }

  // f ... merge function
  template<typename F>
  int unite(int x, int y,const F &f) {
    if ((x = find(x)) == (y = find(y))) return false;
    if (data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    f(x, y);
    return true;
  }

  int size(int k) { return -data[find(k)]; }

  int same(int x, int y) { return find(x) == find(y); }
};

/**
 * @brief Union Find(Disjoint Set Union)
 * @docs docs/data-structure/union-find.md
 */
#line 2 "tree/heavy-light-decomposition.hpp"

#line 2 "graph/graph-template.hpp"

template <typename T>
struct edge {
  int src, to;
  T cost;

  edge(int _to, T _cost) : src(-1), to(_to), cost(_cost) {}
  edge(int _src, int _to, T _cost) : src(_src), to(_to), cost(_cost) {}

  edge &operator=(const int &x) {
    to = x;
    return *this;
  }

  operator int() const { return to; }
};
template <typename T>
using Edges = vector<edge<T>>;
template <typename T>
using WeightedGraph = vector<Edges<T>>;
using UnweightedGraph = vector<vector<int>>;

// Input of (Unweighted) Graph
UnweightedGraph graph(int N, int M = -1, bool is_directed = false,
                      bool is_1origin = true) {
  UnweightedGraph g(N);
  if (M == -1) M = N - 1;
  for (int _ = 0; _ < M; _++) {
    int x, y;
    cin >> x >> y;
    if (is_1origin) x--, y--;
    g[x].push_back(y);
    if (!is_directed) g[y].push_back(x);
  }
  return g;
}

// Input of Weighted Graph
template <typename T>
WeightedGraph<T> wgraph(int N, int M = -1, bool is_directed = false,
                        bool is_1origin = true) {
  WeightedGraph<T> g(N);
  if (M == -1) M = N - 1;
  for (int _ = 0; _ < M; _++) {
    int x, y;
    cin >> x >> y;
    T c;
    cin >> c;
    if (is_1origin) x--, y--;
    g[x].emplace_back(x, y, c);
    if (!is_directed) g[y].emplace_back(y, x, c);
  }
  return g;
}

// Input of Edges
template <typename T>
Edges<T> esgraph(int N, int M, int is_weighted = true, bool is_1origin = true) {
  Edges<T> es;
  for (int _ = 0; _ < M; _++) {
    int x, y;
    cin >> x >> y;
    T c;
    if (is_weighted)
      cin >> c;
    else
      c = 1;
    if (is_1origin) x--, y--;
    es.emplace_back(x, y, c);
  }
  return es;
}

// Input of Adjacency Matrix
template <typename T>
vector<vector<T>> adjgraph(int N, int M, T INF, int is_weighted = true,
                           bool is_directed = false, bool is_1origin = true) {
  vector<vector<T>> d(N, vector<T>(N, INF));
  for (int _ = 0; _ < M; _++) {
    int x, y;
    cin >> x >> y;
    T c;
    if (is_weighted)
      cin >> c;
    else
      c = 1;
    if (is_1origin) x--, y--;
    d[x][y] = c;
    if (!is_directed) d[y][x] = c;
  }
  return d;
}

/**
 * @brief グラフテンプレート
 * @docs docs/graph/graph-template.md
 */
#line 4 "tree/heavy-light-decomposition.hpp"

template <typename G>
struct HeavyLightDecomposition {
 private:
  void dfs_sz(int cur) {
    size[cur] = 1;
    for (auto& dst : g[cur]) {
      if (dst == par[cur]) {
        if (g[cur].size() >= 2 && int(dst) == int(g[cur][0]))
          swap(g[cur][0], g[cur][1]);
        else
          continue;
      }
      depth[dst] = depth[cur] + 1;
      par[dst] = cur;
      dfs_sz(dst);
      size[cur] += size[dst];
      if (size[dst] > size[g[cur][0]]) {
        swap(dst, g[cur][0]);
      }
    }
  }

  void dfs_hld(int cur) {
    down[cur] = id++;
    for (auto dst : g[cur]) {
      if (dst == par[cur]) continue;
      nxt[dst] = (int(dst) == int(g[cur][0]) ? nxt[cur] : int(dst));
      dfs_hld(dst);
    }
    up[cur] = id;
  }

  // [u, v)
  vector<pair<int, int>> ascend(int u, int v) const {
    vector<pair<int, int>> res;
    while (nxt[u] != nxt[v]) {
      res.emplace_back(down[u], down[nxt[u]]);
      u = par[nxt[u]];
    }
    if (u != v) res.emplace_back(down[u], down[v] + 1);
    return res;
  }

  // (u, v]
  vector<pair<int, int>> descend(int u, int v) const {
    if (u == v) return {};
    if (nxt[u] == nxt[v]) return {{down[u] + 1, down[v]}};
    auto res = descend(u, par[nxt[v]]);
    res.emplace_back(down[nxt[v]], down[v]);
    return res;
  }

 public:
  G& g;
  int id;
  vector<int> size, depth, down, up, nxt, par;
  HeavyLightDecomposition(G& _g, int root = 0)
      : g(_g),
        id(0),
        size(g.size(), 0),
        depth(g.size(), 0),
        down(g.size(), -1),
        up(g.size(), -1),
        nxt(g.size(), root),
        par(g.size(), root) {
    dfs_sz(root);
    dfs_hld(root);
  }

  void build(int root) {
    dfs_sz(root);
    dfs_hld(root);
  }

  pair<int, int> idx(int i) const { return make_pair(down[i], up[i]); }

  template <typename F>
  void path_query(int u, int v, bool vertex, const F& f) {
    int l = lca(u, v);
    for (auto&& [a, b] : ascend(u, l)) {
      int s = a + 1, t = b;
      s > t ? f(t, s) : f(s, t);
    }
    if (vertex) f(down[l], down[l] + 1);
    for (auto&& [a, b] : descend(l, v)) {
      int s = a, t = b + 1;
      s > t ? f(t, s) : f(s, t);
    }
  }

  template <typename F>
  void path_noncommutative_query(int u, int v, bool vertex, const F& f) {
    int l = lca(u, v);
    for (auto&& [a, b] : ascend(u, l)) f(a + 1, b);
    if (vertex) f(down[l], down[l] + 1);
    for (auto&& [a, b] : descend(l, v)) f(a, b + 1);
  }

  template <typename F>
  void subtree_query(int u, bool vertex, const F& f) {
    f(down[u] + int(!vertex), up[u]);
  }

  int lca(int a, int b) {
    while (nxt[a] != nxt[b]) {
      if (down[a] < down[b]) swap(a, b);
      a = par[nxt[a]];
    }
    return depth[a] < depth[b] ? a : b;
  }

  int dist(int a, int b) { return depth[a] + depth[b] - depth[lca(a, b)] * 2; }
};

/**
 * @brief Heavy Light Decomposition(重軽分解)
 * @docs docs/tree/heavy-light-decomposition.md
 */
#line 8 "graph/funtional-graph.hpp"

using namespace std;

template <typename T>
struct Namori {
  using G = WeightedGraph<T>;

  int n;
  G g;

  // 部分グラフ
  vector<G> aux;

  // ループ部分の(頂点,辺の重み)
  // loop[i].se は loop[i] と loop[i+1] の間の辺
  vector<pair<int, T>> loop;

  // 頂点の対応関係
  vector<pair<int, int>> mp;

  // HL分解
  vector<HeavyLightDecomposition<G>> hld;

  Namori(int _n = 0) : _uf(_n) { init(_n); }

  void init(int _n) {
    n = _n;
    g.resize(n);
    _uf.data.resize(n);
    fill(begin(_uf.data), end(_uf.data), -1);
    _is_loop.resize(n, false);
    mp.resize(n, make_pair(-1, -1));
  }

  void add_edge(int u, int v, T w = 1) {
    assert(_built == false);
    if (_uf.same(u, v)) {
      _root = u, _adj = v, _w = w;
    } else {
      _uf.unite(u, v);
      g[u].emplace_back(u, v, w);
      g[v].emplace_back(v, u, w);
    }
    if (++_es == n) build();
  }

  void build() {
    if (_built) return;

    _buf.resize(n, -1);
    dfs1(_root, -1);

    for (int c = _adj; c >= 0; c = _buf[c]) {
      loop.emplace_back(c, -1);
      _is_loop[c] = true;
      for (auto& e : g[c]) {
        if (e == _buf[c]) loop.back().second = e.cost;
      }
    }
    assert(loop.back().first == _root);
    loop.back().second = _w;

    _h.resize(n);
    for (auto& [i, _] : loop) dfs2(i, -1);

    fill(begin(_buf), end(_buf), 0);
    for (auto& [i, _] : loop) dfs3(i);

    _uf.data.clear();
    _buf.clear();
    _is_loop.clear();

    aux.resize(loop.size());
    for (int i = 0; i < (int)loop.size(); i++) {
      int k = loop[i].first, j = 0;
      dfs4(k, i, j);
      aux[i].resize(j);

      dfs5(k);
      hld.emplace_back(aux[i]);
    }

    _h.clear();
    _built = true;
  }

  pair<int, int> idx(int i) const { return mp[i]; }

  int root(int i) const { return loop[mp[i].first].first; }

 private:
  // 初期化用の状態変数
  UnionFind _uf;
  vector<int> _buf;
  vector<bool> _is_loop;
  int _root = -1, _adj = -1, _es = 0;
  bool _built = false;
  T _w = 0;
  G _h;

  // parをメモする
  void dfs1(int c, int p) {
    for (auto& d : g[c]) {
      if (d != p) {
        _buf[d] = c;
        dfs1(d, c);
      }
    }
  }

  // _h で有向木を作る
  void dfs2(int c, int p) {
    for (auto& d : g[c]) {
      if (d == p or _is_loop[d]) continue;
      _h[c].emplace_back(c, d, d.cost);
      dfs2(d, c);
    }
  }

  // HLD用に順番替え
  void dfs3(int c) {
    _buf[c] = 1;
    for (auto& d : _h[c]) {
      dfs3(d);
      _buf[c] += _buf[d];
      if (_buf[d] > _buf[_h[c][0]]) {
        swap(_h[c][0], d);
      }
    }
  }

  // 順番をつける
  void dfs4(int c, int i, int& j) {
    mp[c] = make_pair(i, j++);
    for (auto& d : _h[c]) {
      dfs4(d, i, j);
    }
  }

  // 部分グラフを作る
  void dfs5(int c) {
    for (auto& d : _h[c]) {
      dfs5(d);
      auto [i, j] = mp[c];
      auto [_, k] = mp[d];
      aux[i][j].emplace_back(j, k, d.cost);
      // 逆辺も入れたいときはここをオンにする(動くか不明)
      // aux[i][k].emplace_back(k, j, d.cost);
    }
  }
};

/**
 * @brief Functional Graph(なもりグラフ)の分解
 * @docs docs/graph/functional-graph.md
 */
Back to top page