|
| 1 | +#pragma once |
| 2 | +#include <cassert> |
| 3 | +#include <utility> |
| 4 | +#include <vector> |
| 5 | + |
| 6 | +// Euler tour |
| 7 | +// https://maspypy.com/euler-tour-%E3%81%AE%E3%81%8A%E5%8B%89%E5%BC%B7 |
| 8 | +struct euler_tour { |
| 9 | + int n; |
| 10 | + int root; |
| 11 | + |
| 12 | + std::vector<std::pair<int, int>> edges; // (parent, child) |
| 13 | + |
| 14 | + // - 頂点 v に関する部分木に含まれる辺は, [begins[v], ends[v]) に 2 回ずつ登場 |
| 15 | + // - [begins[u], begins[v]) (begins[u] <= begins[v]) の半開区間に u-v パスを構成する辺が奇数回登場 |
| 16 | + std::vector<int> begins; |
| 17 | + std::vector<int> ends; |
| 18 | + |
| 19 | + std::vector<int> par_eid; |
| 20 | + std::vector<std::pair<int, bool>> tour; // (edge_id, flg) flg=true: down, false: up |
| 21 | + |
| 22 | + void _build_dfs(int now, int prv_eid, const std::vector<std::vector<std::pair<int, int>>> &to) { |
| 23 | + tour.emplace_back(prv_eid, true); |
| 24 | + begins[now] = tour.size(); |
| 25 | + |
| 26 | + for (auto [nxt, eid] : to[now]) { |
| 27 | + if (eid == prv_eid) continue; |
| 28 | + par_eid[nxt] = eid; |
| 29 | + if (edges[eid].first == nxt) std::swap(edges[eid].first, edges[eid].second); |
| 30 | + _build_dfs(nxt, eid, to); |
| 31 | + } |
| 32 | + |
| 33 | + ends[now] = tour.size(); |
| 34 | + tour.emplace_back(prv_eid, false); |
| 35 | + } |
| 36 | + |
| 37 | + euler_tour() = default; |
| 38 | + |
| 39 | + euler_tour(int n, const std::vector<std::pair<int, int>> &edges_, int root) |
| 40 | + : n(n), root(root), edges(edges_), begins(n, -1), ends(n, -1), par_eid(n, -1) { |
| 41 | + std::vector<std::vector<std::pair<int, int>>> to(n); |
| 42 | + for (int eid = 0; eid < (int)edges.size(); ++eid) { |
| 43 | + auto [u, v] = edges[eid]; |
| 44 | + assert(u != v); |
| 45 | + to.at(u).emplace_back(v, eid); |
| 46 | + to.at(v).emplace_back(u, eid); |
| 47 | + } |
| 48 | + |
| 49 | + _build_dfs(root, -1, to); |
| 50 | + } |
| 51 | + |
| 52 | + // 頂点 v の部分木の頂点数 |
| 53 | + int subtree_size(int v) const { return (ends.at(v) - begins.at(v)) / 2 + 1; } |
| 54 | + |
| 55 | + int par(int v) const { |
| 56 | + int eid = par_eid.at(v); |
| 57 | + return eid == -1 ? -1 : edges[eid].first; |
| 58 | + } |
| 59 | + |
| 60 | + int tour_child(int idx) const { |
| 61 | + int eid = tour.at(idx).first; |
| 62 | + return eid < 0 ? root : edges[eid].second; |
| 63 | + } |
| 64 | +}; |
0 commit comments