結果
問題 | No.1094 木登り / Climbing tree |
ユーザー |
![]() |
提出日時 | 2021-02-11 18:48:59 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 593 ms / 2,000 ms |
コード長 | 14,779 bytes |
コンパイル時間 | 2,981 ms |
コンパイル使用メモリ | 220,236 KB |
最終ジャッジ日時 | 2025-01-18 17:37:14 |
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 26 |
コンパイルメッセージ
main.cpp: In function ‘int main()’: main.cpp:441:22: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result] 441 | scanf("%d %d %d", &A[i], &B[i], &C[i]); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:454:22: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result] 454 | scanf("%d %d", &s, &t); | ~~~~~^~~~~~~~~~~~~~~~~
ソースコード
#include <bits/stdc++.h>using namespace std;#define FOR(i,a,b) for(int i=(a);i<(b);++i)#define REP(i,n) FOR(i,0,n)#define ALL(v) begin(v),end(v)template<typename A, typename B> inline bool chmax(A & a, const B & b) { if (a < b) { a = b; return true; } return false; }template<typename A, typename B> inline bool chmin(A & a, const B & b) { if (a > b) { a = b; return true; } return false; }using ll = long long;using pii = pair<int, int>;constexpr ll INF = 1ll<<30;constexpr ll longINF = 1ll<<60;constexpr ll MOD = 1000000007;constexpr bool debug = false;//---------------------------------//struct HeavyLightDecomposition {using size_type = std::uint_fast32_t;using Graph = std::vector<std::vector<size_type>>;private:size_type bf_n; // グラフの頂点数std::vector<size_type> par_; // [v] := 頂点 v の親の頂点番号(存在しなければ自分自身)std::vector<size_type> sub_size_; // [v] := 頂点 v を根とする部分木のサイズstd::vector<size_type> depth_; // [v] := 頂点 v の元のグラフでの深さstd::vector<size_type> tree_id_; // [v] := 頂点 v が属する木の idstd::vector<size_type> roots_; // [i] := i 番目の木の rootstd::vector<size_type> heavy_map_; // [v] := 頂点 v が属する heavy-path idstd::vector<size_type> head_; // [i] := heavy-path i の最も根に近い頂点番号std::vector<size_type> heavy_size_ ; // [i] := heavy-path i に属する頂点の個数std::vector<size_type> heavy_depth_; // [i] := heavy-path i から根までに通る light-edge の個数// euler-tourstd::vector<size_type> in_; // [v] := 頂点 v の EulerTour 順序(同一 heavy-path 内では連続)std::vector<size_type> out_; // [v] := 頂点 v から出るときの EulerTour 順序std::vector<size_type> euler_map_; // [i] := EulerTour 順序が i であるような頂点// heavy-path doublingstd::vector<std::vector<size_type>> par_dblng_; // [k][i] := heavy-path i から 2^k 回 light-edge を上った先の頂点public:HeavyLightDecomposition(const Graph & g, bool use_lca = false) : HeavyLightDecomposition(g, g.size(), use_lca) {}HeavyLightDecomposition(const Graph & g, size_type root, bool use_lca) : bf_n(g.size()) {par_.resize(bf_size());sub_size_.resize(bf_size());depth_.resize(bf_size());tree_id_.assign(bf_size(), bf_size());std::vector<size_type> next(bf_size()); // [v] := 頂点 v と同一 heavy-path 内で v より 1 つ葉側の頂点(存在しなければ自分自身)for (size_type i = 0; i < bf_size(); ++i) {if (tree_id_[i] != bf_size()) continue;if (root != bf_size() && i != root) continue;std::stack<std::pair<size_type, size_type>> stk;par_[i] = i;depth_[i] = 0;tree_id_[i] = roots_.size();stk.emplace(i, 0);while (!stk.empty()) {const size_type u = stk.top().first, i = stk.top().second; stk.pop();if (i < g[u].size()) {stk.emplace(u, i + 1);const size_type v = g[u][i];if (v == par_[u]) continue;par_[v] = u;depth_[v] = depth_[u] + 1;tree_id_[v] = roots_.size();stk.emplace(v, 0);}else {size_type mx = 0;next[u] = u;sub_size_[u] = 1;for (size_type v : g[u]) {if (v == par_[u]) continue;sub_size_[u] += sub_size_[v];if (mx < sub_size_[v]) {mx = sub_size_[v];next[u] = v;}}}}roots_.emplace_back(i);}heavy_map_.resize(bf_size());in_.resize(bf_size());out_.resize(bf_size());euler_map_.reserve(bf_size());for (size_type root : roots_) {std::stack<std::pair<size_type, size_type>> stk;heavy_map_[root] = head_.size();head_.emplace_back(root);heavy_size_.emplace_back(1);heavy_depth_.emplace_back(0);stk.emplace(root, 0);while (!stk.empty()) {const size_type u = stk.top().first, i = stk.top().second; stk.pop();if (i < g[u].size()) {stk.emplace(u, i + 1);const size_type v = g[u][i];if (v != par_[u] && v != next[u]) {heavy_map_[v] = head_.size();head_.emplace_back(v);heavy_size_.emplace_back(1);heavy_depth_.emplace_back(heavy_depth_[heavy_map_[u]] + 1);stk.emplace(v, 0);}}if (i == 0) {in_[u] = euler_map_.size();euler_map_.emplace_back(u);const size_type v = next[u];if (v != u) {heavy_map_[v] = heavy_map_[u];++heavy_size_[heavy_map_[u]];stk.emplace(v, 0);}}if (i == g[u].size()) out_[u] = euler_map_.size();}}if (!use_lca) return;size_type max_depth = *std::max_element(begin(heavy_depth_), end(heavy_depth_));size_type lglg_n = 0;while ((1 << lglg_n) < max_depth) ++lglg_n;par_dblng_.assign(lglg_n + 1, std::vector<size_type>(af_size()));for (size_type i = 0; i < af_size(); ++i) par_dblng_[0][i] = par_[head_[i]];for (size_type i = 0; i < lglg_n; ++i) {for (size_type j = 0; j < af_size(); ++j) {par_dblng_[i + 1][j] = par_dblng_[i][heavy_map_[par_dblng_[i][j]]];}}}size_type bf_size() const noexcept { return bf_n; }size_type af_size() const noexcept { return head_.size(); }size_type par(size_type v) const { assert(v < bf_size()); return par_[v]; }size_type sub_size(size_type v) const { assert(v < bf_size()); return sub_size_[v]; }size_type depth(size_type v) const { assert(v < bf_size()); return depth_[v]; }size_type tree_id(size_type v) const { assert(v < bf_size()); return tree_id_[v]; }size_type tree_cnt() const noexcept { return roots_.size(); }const std::vector<size_type> & trees() const noexcept { return roots_; }size_type heavy_map(size_type v) const { assert(v < bf_size()); return heavy_map_[v]; }size_type head(size_type k) const { assert(k < af_size()); return head_[k]; }size_type heavy_size(size_type k) const { assert(k < af_size()); return heavy_size_[k]; }size_type heavy_depth(size_type k) const { assert(k < af_size()); return heavy_depth_[k]; }size_type in(size_type v) const { assert(v < bf_size()); return in_[v]; }size_type out(size_type v) const { assert(v < bf_size()); return out_[v]; }size_type euler_map(size_type k) const { assert(k < bf_size()); return euler_map_[k]; }const std::vector<std::vector<size_type>> & par_dblng() const {assert(!par_dblng_.empty());return par_dblng_;}std::pair<size_type, size_type> get_lca_path(size_type x, size_type y) const {assert(!par_dblng_.empty());assert(x < bf_size());assert(y < bf_size());assert(tree_id_[x] == tree_id_[y]);if (heavy_map_[x] == heavy_map_[y]) return {x, y};bool isswap = heavy_depth_[heavy_map_[x]] < heavy_depth_[heavy_map_[y]];if (isswap) std::swap(x, y);const size_type diff = heavy_depth_[heavy_map_[x]] - heavy_depth_[heavy_map_[y]];for (size_type i = par_dblng_.size(); i > 0; --i) {if (diff >> (i - 1) & 1) x = par_dblng_[i - 1][heavy_map_[x]];}if (heavy_map_[x] == heavy_map_[y]) return isswap ? std::make_pair(y, x) : std::make_pair(x, y);for (size_type i = par_dblng_.size(); i > 0; --i) {const size_type p1 = par_dblng_[i - 1][heavy_map_[x]], p2 = par_dblng_[i - 1][heavy_map_[y]];if (heavy_map_[p1] != heavy_map_[p2]) x = p1, y = p2;}x = par_dblng_[0][heavy_map_[x]];y = par_dblng_[0][heavy_map_[y]];return isswap ? std::make_pair(y, x) : std::make_pair(x, y);}size_type get_lca(size_type x, size_type y) {assert(!par_dblng_.empty());assert(x < bf_size());assert(y < bf_size());std::pair<size_type, size_type> res = get_lca_path(x, y);return in_[res.first] < in_[res.second] ? res.first : res.second;}};template<class HLD, typename T, template<typename> class SEG>struct HeavyLightDecomposition_Query {using value_type = T;using const_reference = const value_type &;using seg_type = SEG<value_type>;using hld_type = HLD;using size_type = std::uint_fast32_t;using Graph = typename hld_type::Graph;using F = std::function<value_type(const_reference, const_reference)>;private:value_type id_elem;F f;hld_type hld;seg_type seg, rseg;bool value_on_vertex;public:HeavyLightDecomposition_Query(const Graph & g, const value_type & id_elem, const F & f, bool value_on_vertex): HeavyLightDecomposition_Query(g, g.size(), id_elem, f, value_on_vertex) {}HeavyLightDecomposition_Query(const Graph & g, size_type root, const value_type & id_elem, const F & f, bool value_on_vertex): id_elem(id_elem), f(f), hld(g, root, false), value_on_vertex(value_on_vertex) {seg = seg_type{ hld.bf_size(), id_elem, f };rseg = seg_type{ hld.bf_size(), id_elem, f };}template<typename U>HeavyLightDecomposition_Query(const Graph & g, const std::vector<U> & v, const value_type & id_elem, const F & f): HeavyLightDecomposition_Query(g, g.size(), v, id_elem, f) {}template<typename U>HeavyLightDecomposition_Query(const Graph & g, size_type root, const std::vector<U> & v, const value_type & id_elem, const F & f): id_elem(id_elem), f(f), hld(g, root, false), value_on_vertex(true) {std::vector<value_type> init(hld.bf_size());for (size_type i = 0; i < hld.bf_size(); ++i) init[i] = v[hld.euler_map(i)];seg = seg_type{ init, id_elem, f };for (size_type i = 0; i < hld.af_size(); ++i) {const size_type fidx = hld.in(hld.head(i));std::reverse(begin(init) + fidx, begin(init) + fidx + hld.heavy_size(i));}rseg = seg_type{ init, id_elem, f };}const hld_type & get_hld() const {return hld;}void set(size_type v, const_reference x) {assert(value_on_vertex);assert(v < hld.bf_size());set_(v, x);}value_type get(size_type v) const {assert(value_on_vertex);assert(v < hld.bf_size());return get_(v);}void set(size_type u, size_type v, const_reference x) {assert(!value_on_vertex);assert(u < hld.bf_size());assert(v < hld.bf_size());assert(hld.par(u) == v || hld.par(v) == u);set_(hld.par(u) == v ? u : v, x);}value_type get(size_type u, size_type v) const {assert(!value_on_vertex);assert(u < hld.bf_size());assert(v < hld.bf_size());assert(hld.par(u) == v || hld.par(v) == u);return get_(hld.par(u) == v ? u : v);}private:void set_(size_type v, const_reference x) {seg.set(hld.in(v), x);rseg.set(reverse_idx(v), x);}value_type get_(size_type v) const {return seg.get(hld.in(v));}public:value_type fold(size_type u, size_type v) const {assert(u < hld.bf_size());assert(v < hld.bf_size());assert(hld.tree_id(u) == hld.tree_id(v));value_type lv = id_elem, rv = id_elem;while (hld.heavy_map(u) != hld.heavy_map(v)) {if (hld.heavy_depth(hld.heavy_map(u)) >= hld.heavy_depth(hld.heavy_map(v))) {const size_type head = hld.head(hld.heavy_map(u));lv = f(lv, rseg.fold(reverse_idx(u), reverse_idx(head) + 1));u = hld.par(head);}if (hld.heavy_map(u) == hld.heavy_map(v)) break;if (hld.heavy_depth(hld.heavy_map(u)) <= hld.heavy_depth(hld.heavy_map(v))) {const size_type head = hld.head(hld.heavy_map(v));rv = f(seg.fold(hld.in(head), hld.in(v) + 1), rv);v = hld.par(head);}}const size_type id = hld.heavy_map(u);if (hld.in(u) < hld.in(v)) rv = f(seg.fold(hld.in(u) + !value_on_vertex, hld.in(v) + 1), rv);else lv = f(lv, rseg.fold(reverse_idx(u), reverse_idx(v) + value_on_vertex));return f(lv, rv);}value_type subtree_sum(size_type v) const {return seg.fold(hld.in(v), hld.out(v));}private:size_type reverse_idx(size_type v) const {const size_type id = hld.heavy_map(v);return (hld.in(hld.head(id)) << 1) + hld.heavy_size(id) - hld.in(v) - 1;}};template<typename T>struct SegmentTree {using value_type = T;using const_reference = const value_type &;using F = std::function<value_type(const_reference, const_reference)>;using size_type = std::size_t;private:size_type n, n_;value_type id_elem;F f;std::vector<value_type> node;public:SegmentTree() = default;SegmentTree(size_type n, const_reference id_elem, const F & f) : n(n), id_elem(id_elem), f(f) {n_ = 1;while (n_ < n) n_ <<= 1;node.resize(2 * n_, id_elem);}SegmentTree(std::vector<value_type> v, const_reference id_elem, const F & f) :SegmentTree(v.size(), id_elem, f) {for (size_type i = 0; i < v.size(); ++i) node[i + n_] = v[i];for (size_type i = n_ - 1; i > 0; --i) node[i] = f(node[i << 1], node[i << 1 | 1]);}size_type size() const noexcept {return n;}void set(size_type i, const_reference x) {assert(i < size());node[i += n_] = x;while (i > 1) {i >>= 1;node[i] = f(node[i << 1], node[i << 1 | 1]);}}const_reference get(size_type i) const {assert(i < size());return node[i + n_];}value_type fold(size_type l, size_type r) const {assert(l <= r);assert(r <= size());value_type lv = id_elem, rv = id_elem;for (l += n_, r += n_; l < r; l >>= 1, r >>= 1) {if (l & 1) lv = f(lv, node[l++]);if (r & 1) rv = f(node[r - 1], rv);}return f(lv, rv);}const_reference fold_all() const {return node[1];}size_type max_right(size_type l, std::function<bool(const_reference)> g) const {assert(l <= size());assert(g(id_elem));if (l == size()) return size();l += n_;value_type sum = id_elem;while (true) {while (~l & 1) l >>= 1;const value_type nex_sum = f(sum, node[l]);if (g(nex_sum)) { sum = nex_sum; ++l; }else break;if ((l & -l) == l) return size();}while (l < n_) {const value_type nex_sum = f(sum, node[l << 1]);l <<= 1;if (g(nex_sum)) { sum = nex_sum; l |= 1; }}return l - n_;}size_type min_left(size_type r, std::function<bool(const_reference)> g) const {assert(r <= size());assert(g(id_elem));if (r == 0) return 0;r += n_;value_type sum = id_elem;while (true) {--r;while (r > 1 && (r & 1)) r >>= 1;const value_type nex_sum = f(node[r], sum);if (g(nex_sum)) sum = nex_sum;else break;if ((r & -r) == r) return 0;}while (r < n_) {const value_type nex_sum = f(node[r << 1 | 1], sum);r <<= 1;if (!g(nex_sum)) r |= 1;else sum = nex_sum;}return r + 1 - n_;}};int main() {int N;cin >> N;vector<int> A(N), B(N), C(N);HeavyLightDecomposition::Graph g(N);REP(i, N - 1) {scanf("%d %d %d", &A[i], &B[i], &C[i]);--A[i]; --B[i];g[A[i]].emplace_back(B[i]);g[B[i]].emplace_back(A[i]);}HeavyLightDecomposition_Query<HeavyLightDecomposition, int, SegmentTree> hld(g, 0, [](int a, int b) { return a + b; }, false);REP(i, N - 1) hld.set(A[i], B[i], C[i]);int Q;cin >> Q;while (Q--) {int s, t;scanf("%d %d", &s, &t);--s; --t;printf("%d\n", hld.fold(s, t));}}