kyopro-lib

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

View on GitHub

:x: test/yosupo-judge/dynamic_tree_vertex_add_path_sum/main.link_cut_tree.test.cpp

Depends on

Code

#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;
}
Back to top page