Library

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

View the Project on GitHub noshi91/Library

:warning: Parametric Heap i64
(data_structure/parametric_heap_i64.cpp)

Code

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <set>
#include <utility>

class parametric_heap {
  using i64 = std::int64_t;

  static constexpr i64 floor_div(const i64 n, const i64 d) {
    return n / d + ((n ^ d) < 0 && n % d);
  }

  class line {
  public:
    i64 a;
    i64 b;

    line(const i64 a_, const i64 b_) : a(a_), b(b_) {}
  };

  class node_type;

  using link_type = std::unique_ptr<node_type>;

  class leaf_type {
  public:
    i64 a;
    std::multiset<i64> b;

    leaf_type(const i64 a_, const i64 b_) : a(a_), b({b_}) {}

    i64 eval(const i64 x) const { return a * x + (*b.begin()); }
    line get() const { return line(a, *b.begin()); }
  };

  class internal_type {
  public:
    link_type left;
    link_type right;
    i64 x;
    i64 y;

    internal_type(link_type l, link_type r)
        : left(std::move(l)), right(std::move(r)), lc(&left->data.leaf),
          rc(&right->data.leaf) {}

    std::ptrdiff_t bias() const {
      return static_cast<std::ptrdiff_t>(left->rank) -
             static_cast<std::ptrdiff_t>(right->rank);
    }
  };

  class node_type {
  public:
    std::size_t rank;
    i64 la;
    union data_t {
      leaf_type leaf;
      internal_type internal;

      data_t() {}
      ~data_t() {}
    } data;

    node_type(node_type &&x) : rank(x.rank), la(x.la), data() {
      if (x.is_leaf()) {
        new (&data.leaf) leaf_type(std::move(x.data.leaf));
      } else {
        new (&data.internal) internal_type(std::move(x.data.internal));
      }
    }

    node_type(const i64 a, const i64 b) : rank(0), data() {
      new (&data.leaf) leaf_type(a, b);
    }

    node_type(link_type l, link_type r) : rank(1), data() {
      new (&data.internal) internal_type(std::move(l), std::move(r));
    }

    bool is_leaf() const { return rank == 0; }
    bool is_internal() const { return rank != 0; }

    ~node_type() {
      if (is_leaf()) {
        data.leaf.~leaf_type();
      } else {
        data.internal.~internal_type();
      }
    }
  };

  link_type root;

  void update_node(node_type &node) const {
    internal_type &internal = node.data.internal;
    node.rank = std::max(internal.left->rank, internal.right->rank) + 1;
    cont i64 m = internal.right.la;
    const node_type *l = internal.left.get();
    const node_type *r = internal.right.get();
    while (true) {
      if (l->is_leaf()) {
        if (r->is_leaf()) {
          break;
        } else {
          const internal_type &r_in = r->data.internal;
          if (l->data.leaf.eval(r_in.x) > r_in.y) {
            r = r_in.left.get();
          } else {
            r = r_in.right.get();
          }
        }
      } else {
        const internal_type &l_in = l->data.internal;
        if (r->is_leaf()) {
          if(r->data.leaf.eval(l_in.x)<l_in.y){
            
          }
          if (is_necessary(ll, lr, r->data.leaf.get())) {
            l = l_in.right.get();
          } else {
            l = l_in.left.get();
          }
        } else {
          const internal_type &r_in = r->data.internal;
          const line &rl = r_in.lc->get();
          const line &rr = r_in.rc->get();
          if (!is_necessary(ll, lr, rl)) {
            l = l_in.left.get();
          } else if (!is_necessary(lr, rl, rr)) {
            r = r_in.right.get();
          } else if (left_discard(ll, lr, rl, rr, m)) {
            l = l_in.right.get();
          } else {
            r = r_in.left.get();
          }
        }
      }
    }
    internal.lc = &l->data.leaf;
    internal.rc = &r->data.leaf;
  }

  void rotate_left(link_type &ptr) const {
    link_type right = std::move(ptr->data.internal.right);
    ptr->data.internal.right = std::move(right->data.internal.left);
    update_node(*ptr);
    right->data.internal.left = std::move(ptr);
    ptr = std::move(right);
  }

  void rotate_right(link_type &ptr) const {
    link_type left = std::move(ptr->data.internal.left);
    ptr->data.internal.left = std::move(left->data.internal.right);
    update_node(*ptr);
    left->data.internal.right = std::move(ptr);
    ptr = std::move(left);
  }

  void balance(link_type &ptr) const {
    internal_type &internal = ptr->data.internal;
    const std::size_t bias = internal.bias();
    if (bias == 2) {
      if (internal.left->data.internal.bias() == -2) {
        rotate_left(internal.left);
      }
      rotate_right(ptr);
    } else if (bias == -2) {
      if (internal.right->data.internal.bias() == 2) {
        rotate_right(internal.right);
      }
      rotate_left(ptr);
    }
    update_node(*ptr);
  }

public:
  explicit parametric_heap(const Compare comp_ = Compare())
      : comp(comp_), root() {}

  bool empty() const { return !static_cast<bool>(root); }

  void insert(const T &a, const T &b) {
    if (empty()) {
      root = std::make_unique<node_type>(node_type(a, b, comp));
      return;
    }
    const auto insert_rec = [&](const auto &self, link_type &ptr) -> void {
      if (ptr->is_leaf()) {
        leaf_type &leaf = ptr->data.leaf;
        if (comp_f(leaf.a, a)) {
          ptr = std::make_unique<node_type>(
              node_type(std::make_unique<node_type>(node_type(a, b, comp)),
                        std::move(ptr)));
        } else if (comp_f(a, leaf.a)) {
          ptr = std::make_unique<node_type>(
              node_type(std::move(ptr),
                        std::make_unique<node_type>(node_type(a, b, comp))));
        } else {
          leaf.b.insert(b);
        }
        return;
      }
      internal_type &internal = ptr->data.internal;
      if (comp_f(internal.get_mid(), a)) {
        self(self, internal.left);
      } else {
        self(self, internal.right);
      }
      balance(ptr);
    };
    insert_rec(insert_rec, root);
  }

  bool erase(const T &a, const T &b) {
    if (empty()) {
      return false;
    }
    bool res = false;
    const auto erase_rec = [&](const auto &self, link_type &ptr) -> void {
      if (ptr->is_leaf()) {
        leaf_type &leaf = ptr->data.leaf;
        if (!comp_f(leaf.a, a) && !comp_f(a, leaf.a)) {
          const auto itr = leaf.b.find(b);
          if (itr != leaf.b.end()) {
            res = true;
            leaf.b.erase(itr);
            if (leaf.b.empty()) {
              ptr.reset();
            }
          }
        }
        return;
      }
      internal_type &internal = ptr->data.internal;
      if (comp_f(internal.get_mid(), a)) {
        self(self, internal.left);
        if (!internal.left) {
          ptr = std::move(internal.right);
          return;
        }
      } else {
        self(self, internal.right);
        if (!internal.right) {
          ptr = std::move(internal.left);
          return;
        }
      }
      balance(ptr);
    };
    erase_rec(erase_rec, root);
    return res;
  }

  i64 min(const i64 x) const {
    assert(!empty());

    const node_type *ptr = root.get();
    while (ptr->is_internal()) {
      const internal_type &internal = ptr->data.internal;
      if (x <= internal.x) {
        ptr = internal.left.get();
      } else {
        ptr = internal.right.get();
      }
    }

    return ptr->data.leaf.eval(x);
  }
};

/**
 * @brief Parametric Heap i64
 * @docs docs/parametric_heap_i64.md
 */

/*

Reference

[1] Overmars, M. H., & Van Leeuwen, J. (1981).
    Maintenance of configurations in the plane.
    Journal of computer and System Sciences, 23(2), 166-204.

[2] Kaplan, H., Tarjan, R. E., & Tsioutsiouliklis, K. (2001, January).
    Faster kinetic heaps and their use in broadcast scheduling.
    In SODA (Vol. 1, pp. 836-844).

*/
#line 1 "data_structure/parametric_heap_i64.cpp"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <set>
#include <utility>

class parametric_heap {
  using i64 = std::int64_t;

  static constexpr i64 floor_div(const i64 n, const i64 d) {
    return n / d + ((n ^ d) < 0 && n % d);
  }

  class line {
  public:
    i64 a;
    i64 b;

    line(const i64 a_, const i64 b_) : a(a_), b(b_) {}
  };

  class node_type;

  using link_type = std::unique_ptr<node_type>;

  class leaf_type {
  public:
    i64 a;
    std::multiset<i64> b;

    leaf_type(const i64 a_, const i64 b_) : a(a_), b({b_}) {}

    i64 eval(const i64 x) const { return a * x + (*b.begin()); }
    line get() const { return line(a, *b.begin()); }
  };

  class internal_type {
  public:
    link_type left;
    link_type right;
    i64 x;
    i64 y;

    internal_type(link_type l, link_type r)
        : left(std::move(l)), right(std::move(r)), lc(&left->data.leaf),
          rc(&right->data.leaf) {}

    std::ptrdiff_t bias() const {
      return static_cast<std::ptrdiff_t>(left->rank) -
             static_cast<std::ptrdiff_t>(right->rank);
    }
  };

  class node_type {
  public:
    std::size_t rank;
    i64 la;
    union data_t {
      leaf_type leaf;
      internal_type internal;

      data_t() {}
      ~data_t() {}
    } data;

    node_type(node_type &&x) : rank(x.rank), la(x.la), data() {
      if (x.is_leaf()) {
        new (&data.leaf) leaf_type(std::move(x.data.leaf));
      } else {
        new (&data.internal) internal_type(std::move(x.data.internal));
      }
    }

    node_type(const i64 a, const i64 b) : rank(0), data() {
      new (&data.leaf) leaf_type(a, b);
    }

    node_type(link_type l, link_type r) : rank(1), data() {
      new (&data.internal) internal_type(std::move(l), std::move(r));
    }

    bool is_leaf() const { return rank == 0; }
    bool is_internal() const { return rank != 0; }

    ~node_type() {
      if (is_leaf()) {
        data.leaf.~leaf_type();
      } else {
        data.internal.~internal_type();
      }
    }
  };

  link_type root;

  void update_node(node_type &node) const {
    internal_type &internal = node.data.internal;
    node.rank = std::max(internal.left->rank, internal.right->rank) + 1;
    cont i64 m = internal.right.la;
    const node_type *l = internal.left.get();
    const node_type *r = internal.right.get();
    while (true) {
      if (l->is_leaf()) {
        if (r->is_leaf()) {
          break;
        } else {
          const internal_type &r_in = r->data.internal;
          if (l->data.leaf.eval(r_in.x) > r_in.y) {
            r = r_in.left.get();
          } else {
            r = r_in.right.get();
          }
        }
      } else {
        const internal_type &l_in = l->data.internal;
        if (r->is_leaf()) {
          if(r->data.leaf.eval(l_in.x)<l_in.y){
            
          }
          if (is_necessary(ll, lr, r->data.leaf.get())) {
            l = l_in.right.get();
          } else {
            l = l_in.left.get();
          }
        } else {
          const internal_type &r_in = r->data.internal;
          const line &rl = r_in.lc->get();
          const line &rr = r_in.rc->get();
          if (!is_necessary(ll, lr, rl)) {
            l = l_in.left.get();
          } else if (!is_necessary(lr, rl, rr)) {
            r = r_in.right.get();
          } else if (left_discard(ll, lr, rl, rr, m)) {
            l = l_in.right.get();
          } else {
            r = r_in.left.get();
          }
        }
      }
    }
    internal.lc = &l->data.leaf;
    internal.rc = &r->data.leaf;
  }

  void rotate_left(link_type &ptr) const {
    link_type right = std::move(ptr->data.internal.right);
    ptr->data.internal.right = std::move(right->data.internal.left);
    update_node(*ptr);
    right->data.internal.left = std::move(ptr);
    ptr = std::move(right);
  }

  void rotate_right(link_type &ptr) const {
    link_type left = std::move(ptr->data.internal.left);
    ptr->data.internal.left = std::move(left->data.internal.right);
    update_node(*ptr);
    left->data.internal.right = std::move(ptr);
    ptr = std::move(left);
  }

  void balance(link_type &ptr) const {
    internal_type &internal = ptr->data.internal;
    const std::size_t bias = internal.bias();
    if (bias == 2) {
      if (internal.left->data.internal.bias() == -2) {
        rotate_left(internal.left);
      }
      rotate_right(ptr);
    } else if (bias == -2) {
      if (internal.right->data.internal.bias() == 2) {
        rotate_right(internal.right);
      }
      rotate_left(ptr);
    }
    update_node(*ptr);
  }

public:
  explicit parametric_heap(const Compare comp_ = Compare())
      : comp(comp_), root() {}

  bool empty() const { return !static_cast<bool>(root); }

  void insert(const T &a, const T &b) {
    if (empty()) {
      root = std::make_unique<node_type>(node_type(a, b, comp));
      return;
    }
    const auto insert_rec = [&](const auto &self, link_type &ptr) -> void {
      if (ptr->is_leaf()) {
        leaf_type &leaf = ptr->data.leaf;
        if (comp_f(leaf.a, a)) {
          ptr = std::make_unique<node_type>(
              node_type(std::make_unique<node_type>(node_type(a, b, comp)),
                        std::move(ptr)));
        } else if (comp_f(a, leaf.a)) {
          ptr = std::make_unique<node_type>(
              node_type(std::move(ptr),
                        std::make_unique<node_type>(node_type(a, b, comp))));
        } else {
          leaf.b.insert(b);
        }
        return;
      }
      internal_type &internal = ptr->data.internal;
      if (comp_f(internal.get_mid(), a)) {
        self(self, internal.left);
      } else {
        self(self, internal.right);
      }
      balance(ptr);
    };
    insert_rec(insert_rec, root);
  }

  bool erase(const T &a, const T &b) {
    if (empty()) {
      return false;
    }
    bool res = false;
    const auto erase_rec = [&](const auto &self, link_type &ptr) -> void {
      if (ptr->is_leaf()) {
        leaf_type &leaf = ptr->data.leaf;
        if (!comp_f(leaf.a, a) && !comp_f(a, leaf.a)) {
          const auto itr = leaf.b.find(b);
          if (itr != leaf.b.end()) {
            res = true;
            leaf.b.erase(itr);
            if (leaf.b.empty()) {
              ptr.reset();
            }
          }
        }
        return;
      }
      internal_type &internal = ptr->data.internal;
      if (comp_f(internal.get_mid(), a)) {
        self(self, internal.left);
        if (!internal.left) {
          ptr = std::move(internal.right);
          return;
        }
      } else {
        self(self, internal.right);
        if (!internal.right) {
          ptr = std::move(internal.left);
          return;
        }
      }
      balance(ptr);
    };
    erase_rec(erase_rec, root);
    return res;
  }

  i64 min(const i64 x) const {
    assert(!empty());

    const node_type *ptr = root.get();
    while (ptr->is_internal()) {
      const internal_type &internal = ptr->data.internal;
      if (x <= internal.x) {
        ptr = internal.left.get();
      } else {
        ptr = internal.right.get();
      }
    }

    return ptr->data.leaf.eval(x);
  }
};

/**
 * @brief Parametric Heap i64
 * @docs docs/parametric_heap_i64.md
 */

/*

Reference

[1] Overmars, M. H., & Van Leeuwen, J. (1981).
    Maintenance of configurations in the plane.
    Journal of computer and System Sciences, 23(2), 166-204.

[2] Kaplan, H., Tarjan, R. E., & Tsioutsiouliklis, K. (2001, January).
    Faster kinetic heaps and their use in broadcast scheduling.
    In SODA (Vol. 1, pp. 836-844).

*/
Back to top page