library

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

View the Project on GitHub maspypy/library

:heavy_check_mark: ds/unionfind/dynamic_unionfind.hpp

Depends on

Verified with

Code

#include "ds/dynamic_array.hpp"


template <bool PERSISTENT>
struct Dynamic_UnionFind {
  // 経路圧縮なし

  Dynamic_Array<int, PERSISTENT> PA;
  using np = typename decltype(PA)::np;

  Dynamic_UnionFind(int N) : PA(15 * N, -1) {}

  np new_root() { return PA.new_root(); }

  int root(np c, int x) {
    while (1) {
      int p = PA.get(c, x);
      assert(x != p);
      if (p < 0) break;
      x = p;
    }
    return x;
  }

  pair<np, bool> merge(np c, int x, int y) {
    x = root(c, x), y = root(c, y);
    if (x == y) return {c, false};
    if (-PA.get(c, x) < -PA.get(c, y)) swap(x, y);
    int new_sz = PA.get(c, x) + PA.get(c, y);
    c = PA.set(c, x, new_sz);
    assert(PA.get(c, x) == new_sz);
    c = PA.set(c, y, x);
    assert(PA.get(c, y) == x);
    return {c, true};
  }

  ll size(np c, int x) { return -PA.get(c, root(c, x)); }
};
#line 1 "ds/node_pool.hpp"
// マルチテストケースでも確保済み chunk を再利用する
template <class Node>
struct Node_Pool {
  union Slot {
    Node node;
    Slot* next;

    Slot() {}
    ~Slot() {}
  };
  using np = Node*;

  static constexpr int CHUNK_SIZE = 1 << 12;

  vc<unique_ptr<Slot[]>> chunks;
  int chunk_id = 0;
  int pos = 0;
  Slot* free_head = nullptr;

  ~Node_Pool() {
    auto& cache = chunk_cache();
    for (auto& p : chunks) cache.eb(std::move(p));
  }

  template <class... Args>
  np create(Args&&... args) {
    Slot* s = new_slot();
    return ::new (&s->node) Node(forward<Args>(args)...);
  }

  np clone(const np x) {
    assert(x);
    Slot* s = new_slot();
    return ::new (&s->node) Node(*x);
  }

  void destroy(np x) {
    if (!x) return;
    x->~Node();
    Slot* s = reinterpret_cast<Slot*>(x);
    s->next = free_head;
    free_head = s;
  }

  // 全 node を無効化する。
  // 確保済み chunk は解放せず、次回以降に再利用する。
  void reset() {
    free_head = nullptr;
    chunk_id = 0;
    pos = 0;
  }

 private:
  static vc<unique_ptr<Slot[]>>& chunk_cache() {
    // static Node_Pool の destructor より先に破棄されないようにする。
    static auto* cache = new vc<unique_ptr<Slot[]>>();
    return *cache;
  }

  void alloc_chunk() {
    auto& cache = chunk_cache();
    if (cache.empty()) {
      chunks.eb(make_unique<Slot[]>(CHUNK_SIZE));
    } else {
      chunks.eb(std::move(cache.back()));
      cache.pop_back();
    }
  }

  Slot* new_slot() {
    if (free_head) {
      Slot* s = free_head;
      free_head = free_head->next;
      return s;
    }

    if (chunk_id == len(chunks)) alloc_chunk();

    Slot* s = &chunks[chunk_id][pos++];
    if (pos == CHUNK_SIZE) {
      ++chunk_id;
      pos = 0;
    }
    return s;
  }
};
#line 2 "ds/dynamic_array.hpp"

template <typename T, bool PERSISTENT>
struct Dynamic_Array {
  static constexpr int LOG = 4;
  static constexpr int MASK = (1 << LOG) - 1;
  struct Node {
    T x;
    Node* ch[1 << LOG] = {};
  };
  Node_Pool<Node> pool;
  using np = Node*;
  const T x0;

  Dynamic_Array(int NODES, T default_value) : x0(default_value) {}
  np new_root() {
    np c = pool.create();
    c->x = x0;
    fill(c->ch, c->ch + (1 << LOG), nullptr);
    return c;
  }

  np new_node(vc<T> dat) {
    np root = new_root();
    FOR(i, len(dat)) root = set(root, i, dat[i], false);
    return root;
  }

  T get(np c, int idx) {
    if (!c) return x0;
    if (idx == 0) return c->x;
    return get(c->ch[idx & MASK], (idx - 1) >> LOG);
  }

  np set(np c, int idx, T x, bool make_copy = true) {
    c = (c ? clone(c, make_copy) : new_root());
    if (idx == 0) {
      c->x = x;
      return c;
    }
    c->ch[idx & MASK] = set(c->ch[idx & MASK], (idx - 1) >> LOG, x);
    return c;
  }

 private:
  np clone(np c, bool make_copy) {
    if (!make_copy || !PERSISTENT) return c;
    return pool.clone(c);
  }
};
#line 2 "ds/unionfind/dynamic_unionfind.hpp"

template <bool PERSISTENT>
struct Dynamic_UnionFind {
  // 経路圧縮なし

  Dynamic_Array<int, PERSISTENT> PA;
  using np = typename decltype(PA)::np;

  Dynamic_UnionFind(int N) : PA(15 * N, -1) {}

  np new_root() { return PA.new_root(); }

  int root(np c, int x) {
    while (1) {
      int p = PA.get(c, x);
      assert(x != p);
      if (p < 0) break;
      x = p;
    }
    return x;
  }

  pair<np, bool> merge(np c, int x, int y) {
    x = root(c, x), y = root(c, y);
    if (x == y) return {c, false};
    if (-PA.get(c, x) < -PA.get(c, y)) swap(x, y);
    int new_sz = PA.get(c, x) + PA.get(c, y);
    c = PA.set(c, x, new_sz);
    assert(PA.get(c, x) == new_sz);
    c = PA.set(c, y, x);
    assert(PA.get(c, y) == x);
    return {c, true};
  }

  ll size(np c, int x) { return -PA.get(c, root(c, x)); }
};
Back to top page