#define PROBLEM "https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum" #include <iostream> #include "Mylib/AlgebraicStructure/Monoid/sum.cpp" #include "Mylib/DataStructure/LinkCutTree/link_cut_tree.cpp" #include "Mylib/IO/input_tuples.cpp" #include "Mylib/IO/input_tuples_with_index.cpp" namespace hl = haar_lib; int main() { std::cin.tie(0); std::ios::sync_with_stdio(false); int N, Q; std::cin >> N >> Q; hl::link_cut_tree<hl::sum_monoid<int64_t>> lct(N); for (auto [i, a] : hl::input_tuples_with_index<int64_t>(N)) { lct.set(i, a); } for (auto [u, v] : hl::input_tuples<int, int>(N - 1)) { lct.link(u, v); } for (auto [type] : hl::input_tuples<int>(Q)) { switch (type) { case 0: { int u, v, w, x; std::cin >> u >> v >> w >> x; lct.cut(u, v); lct.link(w, x); break; } case 1: { int p, x; std::cin >> p >> x; lct.update(p, x); break; } case 2: { int u, v; std::cin >> u >> v; auto ans = lct.fold(u, v); std::cout << ans << std::endl; break; } } } return 0; }
#line 1 "test/yosupo-judge/dynamic_tree_vertex_add_path_sum/main.link_cut_tree.test.cpp" #define PROBLEM "https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum" #include <iostream> #line 2 "Mylib/AlgebraicStructure/Monoid/sum.cpp" namespace haar_lib { template <typename T> struct sum_monoid { using value_type = T; value_type operator()() const { return 0; } value_type operator()(value_type a, value_type b) const { return a + b; } }; } // namespace haar_lib #line 2 "Mylib/DataStructure/LinkCutTree/link_cut_tree.cpp" #include <vector> namespace haar_lib { template <typename Monoid> struct link_cut_node { using value_type = typename Monoid::value_type; using node = link_cut_node; const static Monoid M; int subsize; node *left, *right, *parent; bool rev; value_type value, result; link_cut_node() : subsize(1), left(nullptr), right(nullptr), parent(nullptr), rev(false), value(M()), result(M()) {} bool is_root() const { return !parent or (parent->left != this and parent->right != this); } void update_node_status() { subsize = 1; result = value; if (left) { left->push_down(); subsize += left->subsize; result = M(result, left->result); } if (right) { right->push_down(); subsize += right->subsize; result = M(result, right->result); } } void push_down() { if (rev) { std::swap(left, right); if (left) left->rev ^= true; if (right) right->rev ^= true; rev = false; } } void rot(int dir_right) { node *p = parent, *g = p->parent; if (dir_right) { if ((p->left = right)) right->parent = p; right = p; p->parent = this; } else { if ((p->right = left)) left->parent = p; left = p; p->parent = this; } p->update_node_status(); update_node_status(); parent = g; if (not g) return; if (g->left == p) g->left = this; if (g->right == p) g->right = this; g->update_node_status(); } void splay() { while (not is_root()) { node *p = parent, *gp = p->parent; if (p->is_root()) { p->push_down(); push_down(); rot(this == p->left); } else { gp->push_down(); p->push_down(); push_down(); bool flag = this == p->left; if ((this == p->left) == (p == gp->left)) { p->rot(flag); rot(flag); } else { rot(flag); rot(not flag); } } } push_down(); } static void expose(node *u) { node *rp = nullptr; for (node *p = u; p; p = p->parent) { p->splay(); p->right = rp; p->update_node_status(); rp = p; } u->splay(); } static void link(node *u, node *v) { evert(u); u->parent = v; } static void cut(node *u) { expose(u); u->left->parent = nullptr; u->left = nullptr; u->update_node_status(); } static void cut(node *u, node *v) { expose(u); expose(v); if (u->is_root()) u->parent = nullptr; else { v->left->parent = nullptr; v->left = nullptr; v->update_node_status(); } } static void evert(node *u) { expose(u); u->rev ^= true; u->push_down(); } }; template <typename Monoid> class link_cut_tree { public: using value_type = typename Monoid::value_type; private: using node = link_cut_node<Monoid>; Monoid M_; int N_; std::vector<node *> nodes_; public: link_cut_tree() {} link_cut_tree(int N) : N_(N), nodes_(N) { for (int i = 0; i < N_; ++i) { nodes_[i] = new node(); } } void expose(int k) { node::expose(nodes_[k]); } void cut(int i, int j) { node::cut(nodes_[i], nodes_[j]); } void link(int i, int j) { node::link(nodes_[i], nodes_[j]); } void evert(int k) { node::evert(nodes_[k]); } void set(int k, value_type x) { node::evert(nodes_[k]); nodes_[k]->value = x; nodes_[k]->push_down(); } void update(int k, value_type x) { set(k, M_(get(k), x)); } value_type get(int k) const { return nodes_[k]->value; } value_type fold(int i, int j) { node::evert(nodes_[i]); node::expose(nodes_[j]); return nodes_[j]->result; } }; } // namespace haar_lib #line 2 "Mylib/IO/input_tuples.cpp" #include <initializer_list> #line 4 "Mylib/IO/input_tuples.cpp" #include <tuple> #include <utility> #line 6 "Mylib/IO/input_tuple.cpp" namespace haar_lib { template <typename T, size_t... I> static void input_tuple_helper(std::istream &s, T &val, std::index_sequence<I...>) { (void) std::initializer_list<int>{(void(s >> std::get<I>(val)), 0)...}; } template <typename T, typename U> std::istream &operator>>(std::istream &s, std::pair<T, U> &value) { s >> value.first >> value.second; return s; } template <typename... Args> std::istream &operator>>(std::istream &s, std::tuple<Args...> &value) { input_tuple_helper(s, value, std::make_index_sequence<sizeof...(Args)>()); return s; } } // namespace haar_lib #line 8 "Mylib/IO/input_tuples.cpp" namespace haar_lib { template <typename... Args> class InputTuples { struct iter { using value_type = std::tuple<Args...>; value_type value; bool fetched = false; int N, c = 0; value_type operator*() { if (not fetched) { std::cin >> value; } return value; } void operator++() { ++c; fetched = false; } bool operator!=(iter &) const { return c < N; } iter(int N) : N(N) {} }; int N; public: InputTuples(int N) : N(N) {} iter begin() const { return iter(N); } iter end() const { return iter(N); } }; template <typename... Args> auto input_tuples(int N) { return InputTuples<Args...>(N); } } // namespace haar_lib #line 8 "Mylib/IO/input_tuples_with_index.cpp" namespace haar_lib { template <typename... Args> class InputTuplesWithIndex { struct iter { using value_type = std::tuple<int, Args...>; value_type value; bool fetched = false; int N; int c = 0; value_type operator*() { if (not fetched) { std::tuple<Args...> temp; std::cin >> temp; value = std::tuple_cat(std::make_tuple(c), temp); } return value; } void operator++() { ++c; fetched = false; } bool operator!=(iter &) const { return c < N; } iter(int N) : N(N) {} }; int N; public: InputTuplesWithIndex(int N) : N(N) {} iter begin() const { return iter(N); } iter end() const { return iter(N); } }; template <typename... Args> auto input_tuples_with_index(int N) { return InputTuplesWithIndex<Args...>(N); } } // namespace haar_lib #line 8 "test/yosupo-judge/dynamic_tree_vertex_add_path_sum/main.link_cut_tree.test.cpp" namespace hl = haar_lib; int main() { std::cin.tie(0); std::ios::sync_with_stdio(false); int N, Q; std::cin >> N >> Q; hl::link_cut_tree<hl::sum_monoid<int64_t>> lct(N); for (auto [i, a] : hl::input_tuples_with_index<int64_t>(N)) { lct.set(i, a); } for (auto [u, v] : hl::input_tuples<int, int>(N - 1)) { lct.link(u, v); } for (auto [type] : hl::input_tuples<int>(Q)) { switch (type) { case 0: { int u, v, w, x; std::cin >> u >> v >> w >> x; lct.cut(u, v); lct.link(w, x); break; } case 1: { int p, x; std::cin >> p >> x; lct.update(p, x); break; } case 2: { int u, v; std::cin >> u >> v; auto ans = lct.fold(u, v); std::cout << ans << std::endl; break; } } } return 0; }