This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "src/data_structure/tree.hpp"GNU pbds の tree を用いて
k 番目に小さい要素の取得x 未満 / 以下の要素数の取得x 以上 / より大きい最小要素の取得x 以下 / 未満の最大要素の取得を高速に行うことができるデータ構造。
OfflineTree と異なり,扱う値を事前に列挙する必要がなく,任意の値を後から insert できる。
T の < に従うk は 0-indexed
Multi = false のとき,同じ値は 2 回以上入らないMulti = true のとき,同じ値を複数個持つことができるtemplate <class T, bool Multi = false>
struct OnlineTree;
T:比較可能な型
std::less<T>pbds::tree 上での順序比較が使用できる必要がある。
Multi:重複を許すかどうか
false:集合として扱うtrue:多重集合として扱うまた,次の alias が定義されている。
template <class T>
using OnlineSet = OnlineTree<T, false>;
template <class T>
using OnlineMultiSet = OnlineTree<T, true>;
OnlineTree<T, Multi>()
空の OnlineTree を作る。
計算量
\[O(1)\]int count(const T& x) const
現在含まれている x の個数を返す。
Multi = false のとき,返り値は 0 または 1
Multi = true のとき,返り値は現在の多重度計算量
\[O(\log n)\]bool contains(const T& x) const
x が現在集合に含まれていれば true,そうでなければ false を返す。
Multi = true の場合は,x の個数が 1 個以上なら true を返す。
計算量
\[O(\log n)\]bool insert(const T& x)
x を追加する。
Multi = false のとき,すでに x が含まれている場合は何もしないMulti = true のとき,すでに x が含まれていても個数を 1 増やす追加に成功したとき true,失敗したとき false を返す。
Multi = true の場合は常に追加できるため,基本的に true を返す。
計算量
\[O(\log n)\]bool erase(const T& x)
x を 1 個削除する。
x が現在 1 個も含まれていない場合は何もしないMulti = true の場合も,削除されるのは 1 個だけである削除に成功したとき true,失敗したとき false を返す。
計算量
\[O(\log n)\]int erase_all(const T& x)
x をすべて削除する。
削除した個数を返す。
x が現在 1 個も含まれていない場合は 0 を返すMulti = false のとき,返り値は 0 または 1
Multi = true のとき,返り値は削除前の x の多重度計算量
Multi = false の場合
Multi = true の場合,削除する個数を $c$ として
int size() const
現在含まれている要素数を返す。
Multi = true の場合は,重複を個別に数える。
例えば 3 が 2 個,5 が 1 個含まれているなら size() は 3 を返す。
計算量
\[O(1)\]bool empty() const
空なら true,そうでなければ false を返す。
計算量
\[O(1)\]int order_of_key(const T& x) const
x 未満の要素数を返す。
pbds の tree::order_of_key に対応する。
Multi = true の場合は,重複を個別に数える。
計算量
\[O(\log n)\]int count_lt(const T& x) const
x 未満の要素数を返す。
order_of_key(x) の別名。
Multi = true の場合は,重複を個別に数える。
計算量
\[O(\log n)\]int count_le(const T& x) const
x 以下の要素数を返す。
Multi = true の場合は,重複を個別に数える。
計算量
\[O(\log n)\]std::optional<T> find_by_order(int k) const
k 番目に小さい要素を返す。
ただし k は 0-indexed。
k = 0 は最小要素k = size() - 1 は最大要素範囲外なら std::nullopt を返す。
pbds の tree::find_by_order に対応する。
Multi = true の場合は,重複も別々の要素として数える。
例えば {1, 3, 3, 5} に対して find_by_order(1) と find_by_order(2) はどちらも 3 を返す。
制約
有効な要素を得たいなら
\[0 \le k < |S|\]計算量
\[O(\log n)\]std::optional<T> kth(int k) const
k 番目に小さい要素を返す。
find_by_order(k) の別名。
範囲外なら std::nullopt を返す。
計算量
\[O(\log n)\]std::optional<T> lower_bound(const T& x) const
x 以上の最小要素を返す。
そのような要素が存在しないときは std::nullopt を返す。
Multi = true の場合でも,返す値は 1 つである。
計算量
\[O(\log n)\]std::optional<T> upper_bound(const T& x) const
x より大きい最小要素を返す。
そのような要素が存在しないときは std::nullopt を返す。
Multi = true の場合でも,x と等しい要素はスキップされる。
計算量
\[O(\log n)\]std::optional<T> prev_le(const T& x) const
x 以下の最大要素を返す。
そのような要素が存在しないときは std::nullopt を返す。
Multi = true の場合でも,返す値は 1 つである。
計算量
\[O(\log n)\]std::optional<T> prev_lt(const T& x) const
x 未満の最大要素を返す。
そのような要素が存在しないときは std::nullopt を返す。
Multi = true の場合でも,x と等しい要素はスキップされる。
計算量
\[O(\log n)\]このデータ構造は GNU pbds の tree を用いているため,GCC 環境に依存する。
OfflineTree と異なり,扱いたい値をあらかじめ列挙する必要はない。
そのため,後から現れる値をそのまま insert できる。
Multi = false の場合は集合として振る舞うため,同じ値を複数個は持たない。
Multi = true の場合は多重集合として振る舞い,同じ値を複数個持つことができる。
Multi = true の内部実装では,値 x に一意な ID を付けた組 (x, id) を pbds の tree に格納することで,同じ値を複数個管理している。
#pragma once
#include <cstddef>
#include <limits>
#include <optional>
#include <utility>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
namespace akTARDIGRADE13 {
template <class T, bool Multi = false>
struct OnlineTree;
template <class T>
struct OnlineTree<T, false> {
using tree_type =
__gnu_pbds::tree<T, __gnu_pbds::null_type, std::less<T>, __gnu_pbds::rb_tree_tag,
__gnu_pbds::tree_order_statistics_node_update>;
tree_type st;
OnlineTree() : st() {}
int count(const T& x) const { return st.find(x) != st.end() ? 1 : 0; }
bool contains(const T& x) const { return st.find(x) != st.end(); }
bool insert(const T& x) { return st.insert(x).second; }
bool erase(const T& x) {
auto it = st.find(x);
if (it == st.end()) return false;
st.erase(it);
return true;
}
int erase_all(const T& x) { return erase(x) ? 1 : 0; }
int size() const { return static_cast<int>(st.size()); }
bool empty() const { return st.empty(); }
int order_of_key(const T& x) const { return static_cast<int>(st.order_of_key(x)); }
int count_lt(const T& x) const { return order_of_key(x); }
int count_le(const T& x) const { return order_of_key(x) + count(x); }
std::optional<T> find_by_order(int k) const {
if (k < 0 || k >= size()) return std::nullopt;
auto it = st.find_by_order(static_cast<std::size_t>(k));
if (it == st.end()) return std::nullopt;
return *it;
}
std::optional<T> kth(int k) const { return find_by_order(k); }
std::optional<T> lower_bound(const T& x) const {
auto it = st.lower_bound(x);
if (it == st.end()) return std::nullopt;
return *it;
}
std::optional<T> upper_bound(const T& x) const {
auto it = st.upper_bound(x);
if (it == st.end()) return std::nullopt;
return *it;
}
std::optional<T> prev_le(const T& x) const {
auto it = st.upper_bound(x);
if (it == st.begin()) return std::nullopt;
--it;
return *it;
}
std::optional<T> prev_lt(const T& x) const {
auto it = st.lower_bound(x);
if (it == st.begin()) return std::nullopt;
--it;
return *it;
}
};
template <class T>
struct OnlineTree<T, true> {
using id_type = long long;
using node_type = std::pair<T, id_type>;
static constexpr id_type min_id = std::numeric_limits<id_type>::min();
static constexpr id_type max_id = std::numeric_limits<id_type>::max();
using tree_type =
__gnu_pbds::tree<node_type, __gnu_pbds::null_type, std::less<node_type>,
__gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
tree_type st;
id_type next_id;
OnlineTree() : st(), next_id(0) {}
int count(const T& x) const { return count_le(x) - count_lt(x); }
bool contains(const T& x) const { return count(x) != 0; }
bool insert(const T& x) {
st.insert({x, next_id++});
return true;
}
bool erase(const T& x) {
auto it = st.lower_bound({x, min_id});
if (it == st.end() || it->first != x) return false;
st.erase(it);
return true;
}
int erase_all(const T& x) {
int erased = 0;
auto it = st.lower_bound({x, min_id});
while (it != st.end() && it->first == x) {
auto nxt = it;
++nxt;
st.erase(it);
it = nxt;
++erased;
}
return erased;
}
int size() const { return static_cast<int>(st.size()); }
bool empty() const { return st.empty(); }
int order_of_key(const T& x) const { return static_cast<int>(st.order_of_key({x, min_id})); }
int count_lt(const T& x) const { return order_of_key(x); }
int count_le(const T& x) const { return static_cast<int>(st.order_of_key({x, max_id})); }
std::optional<T> find_by_order(int k) const {
if (k < 0 || k >= size()) return std::nullopt;
auto it = st.find_by_order(static_cast<std::size_t>(k));
if (it == st.end()) return std::nullopt;
return it->first;
}
std::optional<T> kth(int k) const { return find_by_order(k); }
std::optional<T> lower_bound(const T& x) const {
auto it = st.lower_bound({x, min_id});
if (it == st.end()) return std::nullopt;
return it->first;
}
std::optional<T> upper_bound(const T& x) const {
auto it = st.upper_bound({x, max_id});
if (it == st.end()) return std::nullopt;
return it->first;
}
std::optional<T> prev_le(const T& x) const {
auto it = st.upper_bound({x, max_id});
if (it == st.begin()) return std::nullopt;
--it;
return it->first;
}
std::optional<T> prev_lt(const T& x) const {
auto it = st.lower_bound({x, min_id});
if (it == st.begin()) return std::nullopt;
--it;
return it->first;
}
};
template <class T>
using OnlineSet = OnlineTree<T, false>;
template <class T>
using OnlineMultiSet = OnlineTree<T, true>;
} // namespace akTARDIGRADE13
#line 2 "src/data_structure/tree.hpp"
#include <cstddef>
#include <limits>
#include <optional>
#include <utility>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
namespace akTARDIGRADE13 {
template <class T, bool Multi = false>
struct OnlineTree;
template <class T>
struct OnlineTree<T, false> {
using tree_type =
__gnu_pbds::tree<T, __gnu_pbds::null_type, std::less<T>, __gnu_pbds::rb_tree_tag,
__gnu_pbds::tree_order_statistics_node_update>;
tree_type st;
OnlineTree() : st() {}
int count(const T& x) const { return st.find(x) != st.end() ? 1 : 0; }
bool contains(const T& x) const { return st.find(x) != st.end(); }
bool insert(const T& x) { return st.insert(x).second; }
bool erase(const T& x) {
auto it = st.find(x);
if (it == st.end()) return false;
st.erase(it);
return true;
}
int erase_all(const T& x) { return erase(x) ? 1 : 0; }
int size() const { return static_cast<int>(st.size()); }
bool empty() const { return st.empty(); }
int order_of_key(const T& x) const { return static_cast<int>(st.order_of_key(x)); }
int count_lt(const T& x) const { return order_of_key(x); }
int count_le(const T& x) const { return order_of_key(x) + count(x); }
std::optional<T> find_by_order(int k) const {
if (k < 0 || k >= size()) return std::nullopt;
auto it = st.find_by_order(static_cast<std::size_t>(k));
if (it == st.end()) return std::nullopt;
return *it;
}
std::optional<T> kth(int k) const { return find_by_order(k); }
std::optional<T> lower_bound(const T& x) const {
auto it = st.lower_bound(x);
if (it == st.end()) return std::nullopt;
return *it;
}
std::optional<T> upper_bound(const T& x) const {
auto it = st.upper_bound(x);
if (it == st.end()) return std::nullopt;
return *it;
}
std::optional<T> prev_le(const T& x) const {
auto it = st.upper_bound(x);
if (it == st.begin()) return std::nullopt;
--it;
return *it;
}
std::optional<T> prev_lt(const T& x) const {
auto it = st.lower_bound(x);
if (it == st.begin()) return std::nullopt;
--it;
return *it;
}
};
template <class T>
struct OnlineTree<T, true> {
using id_type = long long;
using node_type = std::pair<T, id_type>;
static constexpr id_type min_id = std::numeric_limits<id_type>::min();
static constexpr id_type max_id = std::numeric_limits<id_type>::max();
using tree_type =
__gnu_pbds::tree<node_type, __gnu_pbds::null_type, std::less<node_type>,
__gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
tree_type st;
id_type next_id;
OnlineTree() : st(), next_id(0) {}
int count(const T& x) const { return count_le(x) - count_lt(x); }
bool contains(const T& x) const { return count(x) != 0; }
bool insert(const T& x) {
st.insert({x, next_id++});
return true;
}
bool erase(const T& x) {
auto it = st.lower_bound({x, min_id});
if (it == st.end() || it->first != x) return false;
st.erase(it);
return true;
}
int erase_all(const T& x) {
int erased = 0;
auto it = st.lower_bound({x, min_id});
while (it != st.end() && it->first == x) {
auto nxt = it;
++nxt;
st.erase(it);
it = nxt;
++erased;
}
return erased;
}
int size() const { return static_cast<int>(st.size()); }
bool empty() const { return st.empty(); }
int order_of_key(const T& x) const { return static_cast<int>(st.order_of_key({x, min_id})); }
int count_lt(const T& x) const { return order_of_key(x); }
int count_le(const T& x) const { return static_cast<int>(st.order_of_key({x, max_id})); }
std::optional<T> find_by_order(int k) const {
if (k < 0 || k >= size()) return std::nullopt;
auto it = st.find_by_order(static_cast<std::size_t>(k));
if (it == st.end()) return std::nullopt;
return it->first;
}
std::optional<T> kth(int k) const { return find_by_order(k); }
std::optional<T> lower_bound(const T& x) const {
auto it = st.lower_bound({x, min_id});
if (it == st.end()) return std::nullopt;
return it->first;
}
std::optional<T> upper_bound(const T& x) const {
auto it = st.upper_bound({x, max_id});
if (it == st.end()) return std::nullopt;
return it->first;
}
std::optional<T> prev_le(const T& x) const {
auto it = st.upper_bound({x, max_id});
if (it == st.begin()) return std::nullopt;
--it;
return it->first;
}
std::optional<T> prev_lt(const T& x) const {
auto it = st.lower_bound({x, min_id});
if (it == st.begin()) return std::nullopt;
--it;
return it->first;
}
};
template <class T>
using OnlineSet = OnlineTree<T, false>;
template <class T>
using OnlineMultiSet = OnlineTree<T, true>;
} // namespace akTARDIGRADE13