proconlib

This documentation is automatically generated by competitive-verifier/competitive-verifier

View the Project on GitHub anqooqie/proconlib

:heavy_check_mark: Heavy-light decomposition (tools/hld.hpp)

It takes a tree with $n$ vertices as input. As a preprecessing, it remaps its vertex indices to dfs-ordered ones and its edge indices to dfs-ordered ones. Given a path from $u$ to $v$, it returns some intervals of the dfs-ordered vertex indices, or some intervals of the dfs-ordered edge indices representing the path. It is guaranteed that the number of the intervals is $O(\log n)$.

License

Author

Constructor

hld hld(int n);

It creates a graph with $n$ vertices and $0$ edges.

Constraints

Time Complexity

size

int hld.size();

It returns $n$.

Constraints

Time Complexity

add_edge

void hld.add_edge(int u, int v);

It adds an undirected edge connecting $u$ and $v$ to the graph.

Constraints

Time Complexity

build

void hld.build(int r);

It remaps the vertex indices in the tree to dfs-ordered ones and the edge indices in the tree to dfs-ordered ones. In DFS, the root is $r$.

Constraints

Time Complexity

depth

int hld.depth(int v);

Given a vertex $v$ by the original vertex index, it returns the depth of the vertex.

Constraints

Time Complexity

vparent

int hld.vparent(int v);

Given a vertex $v$ by the original vertex index, it returns the original vertex index of the parent of the vertex.

Constraints

Time Complexity

eparent

int hld.eparent(int v);

Given a vertex $v$ by the original vertex index, it returns the original edge index of the edge between the vertex and the parent of the vertex.

Constraints

Time Complexity

vancestor

int hld.vancestor(int v, int k);

Given a vertex $v$ by the original vertex index, it returns the original vertex index of the $k$-th ancestor of the vertex.

Constraints

Time Complexity

vchildren

struct {
  struct iterator {
    int operator*();
    iterator& operator++();
    iterator operator++(int):
    friend bool operator==(iterator lhs, iterator rhs);
    friend bool operator!=(iterator lhs, iterator rhs);
  };
  iterator begin();
  iterator end();
} hld.vchildren(int v);

Given a vertex $v$ by the original vertex index, it returns the original vertex indices of the children of the vertex.

Constraints

Time Complexity

echildren

const std::vector<int>& hld.echildren(int v);

Given a vertex $v$ by the original vertex index, it returns the original edge indices of the edges between the vertex and the children of the vertex.

Constraints

Time Complexity

vid2dfs

int hld.vid2dfs(int v);

Given a vertex $v$ by the original vertex index, it returns the dfs-ordered vertex index of the vertex.

Constraints

Time Complexity

dfs2vid

int hld.dfs2vid(int i);

Given a vertex $i$ by the dfs-ordered vertex index, it returns the original vertex index of the vertex.

Constraints

Time Complexity

eid2dfs

int hld.eid2dfs(int e);

Given an edge $e$ by the original edge index, it returns the dfs-ordered edge index of the edge.

Constraints

Time Complexity

dfs2eid

int hld.dfs2eid(int i);

Given an edge $i$ by the dfs-ordered edge index, it returns the original edge index of the edge.

Constraints

Time Complexity

lca

int hld.lca(int u, int v);

Given a vertex $u$ and a vertex $v$ by the original vertex indices, it returns the original vertex index of the lowest common ancestor of the vertices.

Constraints

Time Complexity

vsubtree

std::pair<int, int> hld.vsubtree(int v);

Given a vertex $v$ by the original vertex index, it returns the interval of the dfs-ordered vertex indices representing the subtree rooted at the vertex.

Constraints

Time Complexity

esubtree

std::pair<int, int> hld.esubtree(int v);

Given a vertex $v$ by the original vertex index, it returns the interval of the dfs-ordered edge indices representing the edges in the subtree rooted at the vertex.

Constraints

Time Complexity

vpath

std::vector<std::pair<int, int>> hld.vpath(int u, int v);

Given a path from $u$ to $v$ by the original vertex indices, it returns some intervals of the dfs-ordered vertex indices representing the path. It is guaranteed that the number of the intervals is $O(\log n)$.

Constraints

Time Complexity

epath

std::vector<std::pair<int, int>> hld.epath(int u, int v);

Given a path from $u$ to $v$ by the original vertex indices, it returns some intervals of the dfs-ordered edge indices representing the path. It is guaranteed that the number of the intervals is $O(\log n)$.

Constraints

Time Complexity

Depends on

Verified with

Code

#ifndef TOOLS_HLD_HPP
#define TOOLS_HLD_HPP

#include <algorithm>
#include <cassert>
#include <iterator>
#include <limits>
#include <numeric>
#include <ranges>
#include <stack>
#include <utility>
#include <vector>
#include "atcoder/dsu.hpp"
#include "tools/less_by.hpp"
#include "tools/pow2.hpp"

namespace tools {
  class hld {
    bool m_built;
    ::std::vector<::std::vector<int>> m_graph;
    ::std::vector<int> m_edges;
    ::std::vector<int> m_parent;
    ::std::vector<int> m_depth;
    ::atcoder::dsu m_dsu;
    ::std::vector<int> m_out;
    ::std::vector<int> m_vid2dfs;
    ::std::vector<int> m_dfs2vid;
    ::std::vector<int> m_eid2dfs;
    ::std::vector<int> m_dfs2eid;
    ::std::vector<::std::vector<int>> m_ancestors;

  public:
    class vchildren_view : public ::std::ranges::view_interface<vchildren_view> {
      ::tools::hld const *m_parent;
      int m_v;

    public:
      class iterator {
      private:
        ::tools::hld const *m_parent;
        int m_v;
        int m_i;

      public:
        using difference_type = ::std::ptrdiff_t;
        using value_type = int;
        using reference = int;
        using pointer = int*;
        using iterator_category = ::std::input_iterator_tag;

        iterator() = default;
        iterator(::tools::hld const * const parent, const int v, const int i) :
          m_parent(parent),
          m_v(v),
          m_i(i) {
        }

        reference operator*() const {
          return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]] ^ this->m_v;
        }
        iterator& operator++() {
          ++this->m_i;
          return *this;
        }
        iterator operator++(int) {
          const auto self = *this;
          ++*this;
          return self;
        }
        friend bool operator==(const iterator& lhs, const iterator& rhs) {
          return lhs.m_parent == rhs.m_parent && lhs.m_v == rhs.m_v && lhs.m_i == rhs.m_i;
        }
        friend bool operator!=(const iterator& lhs, const iterator& rhs) {
          return !(lhs == rhs);
        }
      };

      vchildren_view() = default;
      vchildren_view(::tools::hld const * const parent, const int v) :
        m_parent(parent),
        m_v(v) {
      }

      iterator begin() const {
        return iterator(this->m_parent, this->m_v, 0);
      };
      iterator end() const {
        return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
      }
    };

    hld() = default;
    explicit hld(const int n) : m_built(false), m_graph(n) {
      assert(n >= 1);
    }

    int size() const {
      return this->m_graph.size();
    }

    void add_edge(const int u, const int v) {
      assert(!this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());
      this->m_graph[u].push_back(this->m_edges.size());
      this->m_graph[v].push_back(this->m_edges.size());
      this->m_edges.push_back(u ^ v);
    }

    void build(const int root) {
      assert(!this->m_built);
      assert(0 <= root && root < this->size());
      assert(::std::ssize(this->m_edges) + 1 == this->size());

      this->m_parent.resize(this->size());
      this->m_depth.resize(this->size());
      this->m_dsu = ::atcoder::dsu(this->size());
      this->m_out.resize(this->size());
      this->m_vid2dfs.resize(this->size());
      this->m_dfs2vid.resize(this->size());
      this->m_eid2dfs.resize(this->m_edges.size());
      this->m_dfs2eid.resize(this->m_edges.size());

      ::std::vector<int> subtree_size(this->size());
      this->m_parent[root] = ::std::numeric_limits<int>::max();
      this->m_depth[root] = 0;
      ::std::stack<::std::pair<int, bool>> stack;
      stack.emplace(root, false);
      stack.emplace(root, true);
      while (!stack.empty()) {
        const auto [here, pre] = stack.top();
        stack.pop();
        if (pre) {
          for (const auto eid : this->m_graph[here]) {
            const auto next = this->m_edges[eid] ^ here;
            if (here == root || next != (this->m_edges[this->m_parent[here]] ^ here)) {
              this->m_parent[next] = eid;
              this->m_depth[next] = this->m_depth[here] + 1;
              stack.emplace(next, false);
              stack.emplace(next, true);
            }
          }
        } else {
          subtree_size[here] = 1;
          for (const auto eid : this->m_graph[here]) {
            const auto child = this->m_edges[eid] ^ here;
            if (here == root || child != (this->m_edges[this->m_parent[here]] ^ here)) {
              subtree_size[here] += subtree_size[child];
            }
          }
        }
      }

      for (int v = 0; v < this->size(); ++v) {
        if (v != root) {
          this->m_graph[v].erase(::std::ranges::find(this->m_graph[v], this->m_parent[v]));
        }
        if (this->m_graph[v].size() > 1) {
          ::std::iter_swap(
            this->m_graph[v].begin(),
            ::std::ranges::max_element(
              this->m_graph[v],
              ::tools::less_by([&](const int eid) { return subtree_size[this->m_edges[eid] ^ v]; })
            )
          );
        }
      }

      int dfs_order = 0;
      stack.emplace(root, false);
      stack.emplace(root, true);
      while (!stack.empty()) {
        const auto [here, pre] = stack.top();
        stack.pop();

        if (pre) {
          this->m_vid2dfs[here] = dfs_order;
          this->m_dfs2vid[dfs_order] = here;
          if (here != root) {
            this->m_eid2dfs[this->m_parent[here]] = dfs_order - 1;
            this->m_dfs2eid[dfs_order - 1] = this->m_parent[here];
          }
          ++dfs_order;

          if (!this->m_graph[here].empty()) {
            this->m_dsu.merge(here, this->m_edges[this->m_graph[here].front()] ^ here);
          }
          for (auto it = this->m_graph[here].rbegin(); it != this->m_graph[here].rend(); ++it) {
            stack.emplace(this->m_edges[*it] ^ here, false);
            stack.emplace(this->m_edges[*it] ^ here, true);
          }
        } else {
          this->m_out[here] = dfs_order;
        }
      }

      this->m_built = true;
    }

    int depth(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return this->m_depth[v];
    }
    int vparent(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      assert(this->m_depth[v] > 0);
      return this->m_edges[this->m_parent[v]] ^ v;
    }
    int eparent(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      assert(this->m_depth[v] > 0);
      return this->m_parent[v];
    }
    int vancestor(const int v, const int k) {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      assert(0 <= k && k <= this->m_depth[v]);

      if (this->m_ancestors.empty()) {
        this->m_ancestors.resize(this->size());
        ::std::vector<int> targets(this->size());
        ::std::iota(targets.begin(), targets.end(), 0);
        targets.erase(::std::remove(targets.begin(), targets.end(), this->m_dfs2vid[0]), targets.end());
        for (const auto t : targets) {
          this->m_ancestors[t].push_back(this->vparent(t));
        }
        for (int g = 1; [&]() {
          targets.erase(::std::remove_if(targets.begin(), targets.end(), [&](const int t) {
            return this->m_depth[t] < ::tools::pow2(g);
          }), targets.end());
          return !targets.empty();
        }(); ++g) {
          for (const auto t : targets) {
            this->m_ancestors[t].push_back(this->m_ancestors[this->m_ancestors[t][g - 1]][g - 1]);
          }
        }
      }

      int res = v;
      for (int g = 0; ::tools::pow2(g) <= k; ++g) {
        if ((k >> g) & 1) {
          res = this->m_ancestors[res][g];
        }
      }

      return res;
    }
    ::tools::hld::vchildren_view vchildren(const int v) const & {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return ::tools::hld::vchildren_view(this, v);
    }
    const ::std::vector<int>& echildren(const int v) const & {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return this->m_graph[v];
    }

    int vid2dfs(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return this->m_vid2dfs[v];
    }
    int dfs2vid(const int i) const {
      assert(this->m_built);
      assert(0 <= i && i < this->size());
      return this->m_dfs2vid[i];
    }
    int eid2dfs(const int e) const {
      assert(this->m_built);
      assert(0 <= e && e < this->size());
      return this->m_eid2dfs[e];
    }
    int dfs2eid(const int i) const {
      assert(this->m_built);
      assert(0 <= i && i < this->size());
      return this->m_dfs2eid[i];
    }

    int lca(int u, int v) {
      assert(this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());

      while (!this->m_dsu.same(u, v)) {
        if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
          u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
        } else {
          v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
        }
      }
      if (this->m_depth[u] >= this->m_depth[v]) {
        return v;
      } else {
        return u;
      }
    }

    ::std::pair<int, int> vsubtree(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return ::std::make_pair(this->m_vid2dfs[v], this->m_out[v]);
    }
    ::std::pair<int, int> esubtree(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return ::std::make_pair(this->m_depth[v] == 0 ? 0 : this->m_eid2dfs[this->m_parent[v]] + 1, this->m_out[v] - 1);
    }

    ::std::vector<::std::pair<int, int>> vpath(int u, int v) {
      assert(this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());

      ::std::vector<::std::pair<int, int>> head, tail;
      while (!this->m_dsu.same(u, v)) {
        if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
          head.emplace_back(this->m_vid2dfs[u] + 1, this->m_vid2dfs[this->m_dsu.leader(u)]);
          u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
        } else {
          tail.emplace_back(this->m_vid2dfs[this->m_dsu.leader(v)], this->m_vid2dfs[v] + 1);
          v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
        }
      }
      if (this->m_depth[u] >= this->m_depth[v]) {
        head.emplace_back(this->m_vid2dfs[u] + 1, this->m_vid2dfs[v]);
      } else {
        head.emplace_back(this->m_vid2dfs[u], this->m_vid2dfs[v] + 1);
      }

      ::std::copy(tail.rbegin(), tail.rend(), ::std::back_inserter(head));
      return head;
    }
    ::std::vector<::std::pair<int, int>> epath(int u, int v) {
      assert(this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());

      ::std::vector<::std::pair<int, int>> head, tail;
      while (!this->m_dsu.same(u, v)) {
        if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
          head.emplace_back(this->m_eid2dfs[this->m_parent[u]] + 1, this->m_eid2dfs[this->m_parent[this->m_dsu.leader(u)]]);
          u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
        } else {
          tail.emplace_back(this->m_eid2dfs[this->m_parent[this->m_dsu.leader(v)]], this->m_eid2dfs[this->m_parent[v]] + 1);
          v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
        }
      }
      if (this->m_depth[u] > this->m_depth[v]) {
        head.emplace_back(this->m_eid2dfs[this->m_parent[u]] + 1, this->m_eid2dfs[this->m_graph[v].front()]);
      } else if (this->m_depth[u] < this->m_depth[v]) {
        head.emplace_back(this->m_eid2dfs[this->m_graph[u].front()], this->m_eid2dfs[this->m_parent[v]] + 1);
      }

      ::std::copy(tail.rbegin(), tail.rend(), ::std::back_inserter(head));
      return head;
    }
  };
}

#endif
#line 1 "tools/hld.hpp"



#include <algorithm>
#include <cassert>
#include <iterator>
#include <limits>
#include <numeric>
#include <ranges>
#include <stack>
#include <utility>
#include <vector>
#line 1 "lib/ac-library/atcoder/dsu.hpp"



#line 7 "lib/ac-library/atcoder/dsu.hpp"

namespace atcoder {

// Implement (union by size) + (path compression)
// Reference:
// Zvi Galil and Giuseppe F. Italiano,
// Data structures and algorithms for disjoint set union problems
struct dsu {
  public:
    dsu() : _n(0) {}
    explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

}  // namespace atcoder


#line 1 "tools/less_by.hpp"



namespace tools {

  template <class F>
  class less_by {
  private:
    F selector;

  public:
    less_by(const F& selector) : selector(selector) {
    }

    template <class T>
    bool operator()(const T& x, const T& y) const {
      return selector(x) < selector(y);
    }
  };
}


#line 1 "tools/pow2.hpp"



#include <type_traits>
#include <cstddef>

namespace tools {

  template <typename T, typename ::std::enable_if<::std::is_unsigned<T>::value, ::std::nullptr_t>::type = nullptr>
  constexpr T pow2(const T x) {
    return static_cast<T>(1) << x;
  }

  template <typename T, typename ::std::enable_if<::std::is_signed<T>::value, ::std::nullptr_t>::type = nullptr>
  constexpr T pow2(const T x) {
    return static_cast<T>(static_cast<typename ::std::make_unsigned<T>::type>(1) << static_cast<typename ::std::make_unsigned<T>::type>(x));
  }
}


#line 16 "tools/hld.hpp"

namespace tools {
  class hld {
    bool m_built;
    ::std::vector<::std::vector<int>> m_graph;
    ::std::vector<int> m_edges;
    ::std::vector<int> m_parent;
    ::std::vector<int> m_depth;
    ::atcoder::dsu m_dsu;
    ::std::vector<int> m_out;
    ::std::vector<int> m_vid2dfs;
    ::std::vector<int> m_dfs2vid;
    ::std::vector<int> m_eid2dfs;
    ::std::vector<int> m_dfs2eid;
    ::std::vector<::std::vector<int>> m_ancestors;

  public:
    class vchildren_view : public ::std::ranges::view_interface<vchildren_view> {
      ::tools::hld const *m_parent;
      int m_v;

    public:
      class iterator {
      private:
        ::tools::hld const *m_parent;
        int m_v;
        int m_i;

      public:
        using difference_type = ::std::ptrdiff_t;
        using value_type = int;
        using reference = int;
        using pointer = int*;
        using iterator_category = ::std::input_iterator_tag;

        iterator() = default;
        iterator(::tools::hld const * const parent, const int v, const int i) :
          m_parent(parent),
          m_v(v),
          m_i(i) {
        }

        reference operator*() const {
          return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]] ^ this->m_v;
        }
        iterator& operator++() {
          ++this->m_i;
          return *this;
        }
        iterator operator++(int) {
          const auto self = *this;
          ++*this;
          return self;
        }
        friend bool operator==(const iterator& lhs, const iterator& rhs) {
          return lhs.m_parent == rhs.m_parent && lhs.m_v == rhs.m_v && lhs.m_i == rhs.m_i;
        }
        friend bool operator!=(const iterator& lhs, const iterator& rhs) {
          return !(lhs == rhs);
        }
      };

      vchildren_view() = default;
      vchildren_view(::tools::hld const * const parent, const int v) :
        m_parent(parent),
        m_v(v) {
      }

      iterator begin() const {
        return iterator(this->m_parent, this->m_v, 0);
      };
      iterator end() const {
        return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
      }
    };

    hld() = default;
    explicit hld(const int n) : m_built(false), m_graph(n) {
      assert(n >= 1);
    }

    int size() const {
      return this->m_graph.size();
    }

    void add_edge(const int u, const int v) {
      assert(!this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());
      this->m_graph[u].push_back(this->m_edges.size());
      this->m_graph[v].push_back(this->m_edges.size());
      this->m_edges.push_back(u ^ v);
    }

    void build(const int root) {
      assert(!this->m_built);
      assert(0 <= root && root < this->size());
      assert(::std::ssize(this->m_edges) + 1 == this->size());

      this->m_parent.resize(this->size());
      this->m_depth.resize(this->size());
      this->m_dsu = ::atcoder::dsu(this->size());
      this->m_out.resize(this->size());
      this->m_vid2dfs.resize(this->size());
      this->m_dfs2vid.resize(this->size());
      this->m_eid2dfs.resize(this->m_edges.size());
      this->m_dfs2eid.resize(this->m_edges.size());

      ::std::vector<int> subtree_size(this->size());
      this->m_parent[root] = ::std::numeric_limits<int>::max();
      this->m_depth[root] = 0;
      ::std::stack<::std::pair<int, bool>> stack;
      stack.emplace(root, false);
      stack.emplace(root, true);
      while (!stack.empty()) {
        const auto [here, pre] = stack.top();
        stack.pop();
        if (pre) {
          for (const auto eid : this->m_graph[here]) {
            const auto next = this->m_edges[eid] ^ here;
            if (here == root || next != (this->m_edges[this->m_parent[here]] ^ here)) {
              this->m_parent[next] = eid;
              this->m_depth[next] = this->m_depth[here] + 1;
              stack.emplace(next, false);
              stack.emplace(next, true);
            }
          }
        } else {
          subtree_size[here] = 1;
          for (const auto eid : this->m_graph[here]) {
            const auto child = this->m_edges[eid] ^ here;
            if (here == root || child != (this->m_edges[this->m_parent[here]] ^ here)) {
              subtree_size[here] += subtree_size[child];
            }
          }
        }
      }

      for (int v = 0; v < this->size(); ++v) {
        if (v != root) {
          this->m_graph[v].erase(::std::ranges::find(this->m_graph[v], this->m_parent[v]));
        }
        if (this->m_graph[v].size() > 1) {
          ::std::iter_swap(
            this->m_graph[v].begin(),
            ::std::ranges::max_element(
              this->m_graph[v],
              ::tools::less_by([&](const int eid) { return subtree_size[this->m_edges[eid] ^ v]; })
            )
          );
        }
      }

      int dfs_order = 0;
      stack.emplace(root, false);
      stack.emplace(root, true);
      while (!stack.empty()) {
        const auto [here, pre] = stack.top();
        stack.pop();

        if (pre) {
          this->m_vid2dfs[here] = dfs_order;
          this->m_dfs2vid[dfs_order] = here;
          if (here != root) {
            this->m_eid2dfs[this->m_parent[here]] = dfs_order - 1;
            this->m_dfs2eid[dfs_order - 1] = this->m_parent[here];
          }
          ++dfs_order;

          if (!this->m_graph[here].empty()) {
            this->m_dsu.merge(here, this->m_edges[this->m_graph[here].front()] ^ here);
          }
          for (auto it = this->m_graph[here].rbegin(); it != this->m_graph[here].rend(); ++it) {
            stack.emplace(this->m_edges[*it] ^ here, false);
            stack.emplace(this->m_edges[*it] ^ here, true);
          }
        } else {
          this->m_out[here] = dfs_order;
        }
      }

      this->m_built = true;
    }

    int depth(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return this->m_depth[v];
    }
    int vparent(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      assert(this->m_depth[v] > 0);
      return this->m_edges[this->m_parent[v]] ^ v;
    }
    int eparent(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      assert(this->m_depth[v] > 0);
      return this->m_parent[v];
    }
    int vancestor(const int v, const int k) {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      assert(0 <= k && k <= this->m_depth[v]);

      if (this->m_ancestors.empty()) {
        this->m_ancestors.resize(this->size());
        ::std::vector<int> targets(this->size());
        ::std::iota(targets.begin(), targets.end(), 0);
        targets.erase(::std::remove(targets.begin(), targets.end(), this->m_dfs2vid[0]), targets.end());
        for (const auto t : targets) {
          this->m_ancestors[t].push_back(this->vparent(t));
        }
        for (int g = 1; [&]() {
          targets.erase(::std::remove_if(targets.begin(), targets.end(), [&](const int t) {
            return this->m_depth[t] < ::tools::pow2(g);
          }), targets.end());
          return !targets.empty();
        }(); ++g) {
          for (const auto t : targets) {
            this->m_ancestors[t].push_back(this->m_ancestors[this->m_ancestors[t][g - 1]][g - 1]);
          }
        }
      }

      int res = v;
      for (int g = 0; ::tools::pow2(g) <= k; ++g) {
        if ((k >> g) & 1) {
          res = this->m_ancestors[res][g];
        }
      }

      return res;
    }
    ::tools::hld::vchildren_view vchildren(const int v) const & {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return ::tools::hld::vchildren_view(this, v);
    }
    const ::std::vector<int>& echildren(const int v) const & {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return this->m_graph[v];
    }

    int vid2dfs(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return this->m_vid2dfs[v];
    }
    int dfs2vid(const int i) const {
      assert(this->m_built);
      assert(0 <= i && i < this->size());
      return this->m_dfs2vid[i];
    }
    int eid2dfs(const int e) const {
      assert(this->m_built);
      assert(0 <= e && e < this->size());
      return this->m_eid2dfs[e];
    }
    int dfs2eid(const int i) const {
      assert(this->m_built);
      assert(0 <= i && i < this->size());
      return this->m_dfs2eid[i];
    }

    int lca(int u, int v) {
      assert(this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());

      while (!this->m_dsu.same(u, v)) {
        if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
          u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
        } else {
          v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
        }
      }
      if (this->m_depth[u] >= this->m_depth[v]) {
        return v;
      } else {
        return u;
      }
    }

    ::std::pair<int, int> vsubtree(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return ::std::make_pair(this->m_vid2dfs[v], this->m_out[v]);
    }
    ::std::pair<int, int> esubtree(const int v) const {
      assert(this->m_built);
      assert(0 <= v && v < this->size());
      return ::std::make_pair(this->m_depth[v] == 0 ? 0 : this->m_eid2dfs[this->m_parent[v]] + 1, this->m_out[v] - 1);
    }

    ::std::vector<::std::pair<int, int>> vpath(int u, int v) {
      assert(this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());

      ::std::vector<::std::pair<int, int>> head, tail;
      while (!this->m_dsu.same(u, v)) {
        if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
          head.emplace_back(this->m_vid2dfs[u] + 1, this->m_vid2dfs[this->m_dsu.leader(u)]);
          u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
        } else {
          tail.emplace_back(this->m_vid2dfs[this->m_dsu.leader(v)], this->m_vid2dfs[v] + 1);
          v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
        }
      }
      if (this->m_depth[u] >= this->m_depth[v]) {
        head.emplace_back(this->m_vid2dfs[u] + 1, this->m_vid2dfs[v]);
      } else {
        head.emplace_back(this->m_vid2dfs[u], this->m_vid2dfs[v] + 1);
      }

      ::std::copy(tail.rbegin(), tail.rend(), ::std::back_inserter(head));
      return head;
    }
    ::std::vector<::std::pair<int, int>> epath(int u, int v) {
      assert(this->m_built);
      assert(0 <= u && u < this->size());
      assert(0 <= v && v < this->size());

      ::std::vector<::std::pair<int, int>> head, tail;
      while (!this->m_dsu.same(u, v)) {
        if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
          head.emplace_back(this->m_eid2dfs[this->m_parent[u]] + 1, this->m_eid2dfs[this->m_parent[this->m_dsu.leader(u)]]);
          u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
        } else {
          tail.emplace_back(this->m_eid2dfs[this->m_parent[this->m_dsu.leader(v)]], this->m_eid2dfs[this->m_parent[v]] + 1);
          v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
        }
      }
      if (this->m_depth[u] > this->m_depth[v]) {
        head.emplace_back(this->m_eid2dfs[this->m_parent[u]] + 1, this->m_eid2dfs[this->m_graph[v].front()]);
      } else if (this->m_depth[u] < this->m_depth[v]) {
        head.emplace_back(this->m_eid2dfs[this->m_graph[u].front()], this->m_eid2dfs[this->m_parent[v]] + 1);
      }

      ::std::copy(tail.rbegin(), tail.rend(), ::std::back_inserter(head));
      return head;
    }
  };
}


Back to top page