kyopro-lib

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

View on GitHub

:x: test/yosupo-judge/persistent_unionfind/main.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/persistent_unionfind"

#include <iostream>
#include <vector>
#include "Mylib/DataStructure/UnionFind/persistent_unionfind.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;

  std::vector<hl::persistent_unionfind> G(Q + 1);

  G[0] = hl::persistent_unionfind(N);

  for (auto [i, t, k, u, v] : hl::input_tuples_with_index<int, int, int, int>(Q)) {
    ++k;
    ++i;

    if (t == 0) {
      G[i] = G[k].merge(u, v);
    } else {
      std::cout << G[k].is_same(u, v) << "\n";
    }
  }

  return 0;
}
#line 1 "test/yosupo-judge/persistent_unionfind/main.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/persistent_unionfind"

#include <iostream>
#include <vector>
#line 3 "Mylib/DataStructure/Array/persistent_array.cpp"
#include <memory>
#line 5 "Mylib/DataStructure/Array/persistent_array.cpp"

namespace haar_lib {
  template <typename T>
  class persistent_array {
  public:
    using value_type = T;

  private:
    struct node {
      bool is_terminal;
      int size   = 1;
      node *left = nullptr, *right = nullptr;
      std::unique_ptr<T> value;

      node() : is_terminal(false) {}
      node(T v) : is_terminal(true), value(new T(v)) {}
    };

    size_t size_;
    int depth_;
    node *root_ = nullptr;

    int get_size(node *t) const {
      return t ? t->size : 0;
    }

    node *init(int s, int d) {
      if (s == 0) return nullptr;
      if (d == depth_) {
        return new node(T());
      } else {
        node *t  = new node();
        t->left  = init(s / 2, d + 1);
        t->right = init(s - s / 2, d + 1);
        t->size  = get_size(t->left) + get_size(t->right);
        return t;
      }
    }

    void apply_init(node *t, const std::vector<T> &ret, int &i) {
      if (not t) return;

      if (t->is_terminal) {
        *(t->value) = ret[i];
        ++i;
        return;
      }

      apply_init(t->left, ret, i);
      apply_init(t->right, ret, i);
    }

    persistent_array(node *root) : root_(root) {}

    void calc_depth() {
      depth_ = 1;
      while ((int) size_ > (1 << depth_)) depth_ += 1;
      depth_ += 1;
    }

  public:
    persistent_array() {}
    persistent_array(size_t size) : size_(size) {
      calc_depth();
      root_ = init(size_, 1);
    }

    persistent_array(const std::vector<T> &v) : size_(v.size()) {
      calc_depth();
      root_ = init(size_, 1);

      int i = 0;
      apply_init(root_, v, i);
    }

    persistent_array(const persistent_array &v) {
      this->root_  = v.root_;
      this->size_  = v.size_;
      this->depth_ = v.depth_;
    }

  protected:
    T get(node *t, int i) const {
      if (t->is_terminal) return *(t->value);

      int k = get_size(t->left);
      if (i < k)
        return get(t->left, i);
      else
        return get(t->right, i - k);
    }

  public:
    T operator[](int i) const {
      return get(root_, i);
    }

  protected:
    node *set(node *prev, int i, const T &val) const {
      if (prev->is_terminal) return new node(val);

      int k = get_size(prev->left);

      node *t = new node();
      if (i < k) {
        t->right = prev->right;
        t->left  = set(prev->left, i, val);
        t->size  = get_size(t->right) + get_size(t->left);
      } else {
        t->left  = prev->left;
        t->right = set(prev->right, i - k, val);
        t->size  = get_size(t->right) + get_size(t->left);
      }
      return t;
    }

  public:
    persistent_array set(int i, const T &val) const {
      node *ret = set(root_, i, val);
      return persistent_array(ret);
    }

  protected:
    void traverse(node *t, std::vector<T> &ret) const {
      if (not t) return;

      if (t->is_terminal) {
        ret.push_back(*(t->value));
        return;
      }

      traverse(t->left, ret);
      traverse(t->right, ret);
    }

  public:
    std::vector<T> data() const {
      std::vector<T> ret;
      traverse(root_, ret);
      return ret;
    }
  };
}  // namespace haar_lib
#line 4 "Mylib/DataStructure/UnionFind/persistent_unionfind.cpp"

namespace haar_lib {
  class persistent_unionfind {
    persistent_array<int> par_;

    persistent_unionfind(persistent_array<int> par) : par_(par) {}

  public:
    persistent_unionfind() {}
    persistent_unionfind(int n) : par_(persistent_array<int>(std::vector<int>(n, -1))) {}

    int root_of(int i) const {
      const int p = par_[i];
      if (p < 0) return i;
      return root_of(p);
    }

    bool is_same(int i, int j) const {
      return root_of(i) == root_of(j);
    }

    int size_of(int i) const {
      return -par_[root_of(i)];
    }

    persistent_unionfind merge(int i, int j) const {
      const int ri = root_of(i), rj = root_of(j);
      if (ri == rj) return *this;

      const int size_i = -par_[ri];
      const int size_j = -par_[rj];

      persistent_array<int> ret = par_;

      if (size_i > size_j) {
        ret = ret.set(ri, -(size_i + size_j));
        ret = ret.set(rj, ri);
      } else {
        ret = ret.set(rj, -(size_i + size_j));
        ret = ret.set(ri, rj);
      }

      return persistent_unionfind(ret);
    }
  };
}  // namespace haar_lib
#line 2 "Mylib/IO/input_tuples_with_index.cpp"
#include <initializer_list>
#line 4 "Mylib/IO/input_tuples_with_index.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_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 7 "test/yosupo-judge/persistent_unionfind/main.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;

  std::vector<hl::persistent_unionfind> G(Q + 1);

  G[0] = hl::persistent_unionfind(N);

  for (auto [i, t, k, u, v] : hl::input_tuples_with_index<int, int, int, int>(Q)) {
    ++k;
    ++i;

    if (t == 0) {
      G[i] = G[k].merge(u, v);
    } else {
      std::cout << G[k].is_same(u, v) << "\n";
    }
  }

  return 0;
}
Back to top page