This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub kmyk/competitive-programming-library
/**
* @note almost all operations are O(log N)
*/
template <class T>
class red_black_tree {
enum color_t { BLACK, RED };
struct node_t {
bool is_leaf;
union {
T data;
struct {
color_t m_color;
int m_rank;
int m_size;
node_t *left;
node_t *right;
};
};
node_t() = default;
node_t(T const & a_data)
: is_leaf(true)
, data(a_data) {
}
node_t(node_t *l, node_t *r, color_t c) // non-leaf node
: is_leaf(false)
, m_color(c)
, m_rank(max(rank(l) + (color(l) == BLACK),
rank(r) + (color(r) == BLACK)))
, m_size(size(l) + size(r))
, left(l)
, right(r) {
}
};
struct node_deleter {
void operator () (node_t *t) const {
assert (t != nullptr);
if (not t->is_leaf) {
(*this)(t->right);
(*this)(t->left);
}
delete t;
}
};
static inline color_t color(node_t const *t) {
return t->is_leaf ? BLACK : t->m_color;
}
static inline int rank(node_t const *t) {
return t->is_leaf ? 0 : t->m_rank;
}
static inline int size(node_t const *t) {
return t->is_leaf ? 1 : t->m_size;
}
/**
* @note trees a, b are consumed (at set_left()/set_right())
*/
static node_t *merge(node_t *a, node_t *b) {
if (a == nullptr) return b;
if (b == nullptr) return a;
node_t *c = merge_relax(a, b);
c->m_color = BLACK;
return c;
}
/*
* @note the root of returned tree may violates the color constraint
*/
static node_t *merge_relax(node_t *a, node_t *b) {
if (rank(a) < rank(b)) {
assert (not b->is_leaf);
return set_left(b, merge_relax(a, b->left));
} else if (rank(a) > rank(b)) {
assert (not a->is_leaf);
return set_right(a, merge_relax(a->right, b));
} else {
a->m_color = BLACK;
b->m_color = BLACK;
return new node_t(a, b, RED);
}
}
static node_t *set_left(node_t *b, node_t *c) {
if (b->m_color == BLACK and c->m_color == RED and color(c->left) == RED) {
if (color(b->right) == BLACK) {
*b = node_t(c->right, b->right, RED);
*c = node_t(c->left, b, BLACK);
swap(b, c);
} else {
b->right->m_color = BLACK;
c->m_color = BLACK;
*b = node_t(c, b->right, RED);
}
} else {
*b = node_t(c, b->right, b->m_color);
}
return b;
}
static node_t *set_right(node_t *a, node_t *c) {
if (a->m_color == BLACK and c->m_color == RED and color(c->right) == RED) {
if (color(a->left) == BLACK) {
*a = node_t(a->left, c->left, RED);
*c = node_t(a, c->right, BLACK);
swap(a, c);
} else {
a->left->m_color = BLACK;
c->m_color = BLACK;
*a = node_t(a->left, c, RED);
}
} else {
*a = node_t(a->left, c, a->m_color);
}
return a;
}
/**
* @note tree a is consumed (at explicit delete and merge())
*/
static pair<node_t *, node_t *> split(node_t *a, int k) {
if (k == 0) {
return make_pair( nullptr, a );
}
assert (a != nullptr);
if (k == size(a)) {
return make_pair( a, nullptr );
}
assert (not a->is_leaf);
node_t *a_left = a->left;
node_t *a_right = a->right;
delete a;
if (k < size(a_left)) {
node_t *l, *r; tie(l, r) = split(a_left, k);
return make_pair( l, merge(r, a_right) );
} else if (k > size(a_left)) {
node_t *l, *r; tie(l, r) = split(a_right, k - size(a_left));
return make_pair( merge(a_left, l), r );
} else {
return make_pair( a_left, a_right );
}
}
/**
* @tparam (A, B) = (node_t const *, T const &), (node_t *, T &)
*/
template <class A, class B>
static B get_generic(A a, int i) {
if (a->is_leaf) {
assert (i == 0);
return a->data;
} else {
if (i < size(a->left)) {
return get_generic<A, B>(a->left, i);
} else {
return get_generic<A, B>(a->right, i - size(a->left));
}
}
}
private:
unique_ptr<node_t, node_deleter> root;
public:
red_black_tree<T>() = default;
red_black_tree<T>(node_t *a_root) : root(a_root) {}
static red_black_tree<T> merge(red_black_tree<T> & l, red_black_tree<T> & r) {
node_t *a = l.root.release();
node_t *b = r.root.release();
if (a == nullptr) return red_black_tree<T>(b);
if (b == nullptr) return red_black_tree<T>(a);
return red_black_tree<T>(merge(a, b));
}
pair<red_black_tree<T>, red_black_tree<T> > split(int k) {
assert (0 <= k and k <= size());
node_t *l, *r; tie(l, r) = split(root.release(), k);
return make_pair( red_black_tree<T>(l), red_black_tree<T>(r) );
}
void insert(int i, T const & data) {
assert (0 <= i and i <= size());
if (empty()) {
root.reset(new node_t(data));
return;
} else {
node_t *l, *r; tie(l, r) = split(root.release(), i);
root.reset( merge(merge(l, new node_t(data)), r) );
}
}
void erase(int i) {
assert (0 <= i and i < size());
node_t *l, *r; tie(l, r) = split(root.release(), i + 1);
node_t *m; tie(l, m) = split(l, i);
node_deleter()(m);
root.reset( merge(l, r) );
}
void set(int i, T const & data) {
assert (0 <= i and i < size());
get_generic<node_t *, T &>(root.get(), i) = data;
}
T const & get(int i) const {
assert (0 <= i and i < size());
return get_generic<node_t const *, T const &>(root.get(), i);
}
void push_back(T const & data) {
root.reset( merge(root.release(), new node_t(data)) );
}
void push_front(T const & data) {
root.reset( merge(new node_t(data), root.release()) );
}
void pop_back() {
int k = size() - 1;
auto lr = split(root.release(), k);
root.reset(lr.first);
node_deleter()(lr.second);
}
void pop_front() {
auto lr = split(root.release(), 1);
node_deleter()(lr.first);
root.reset(lr.second);
}
int size() const {
return root ? size(root.get()) : 0;
}
bool empty() const {
return not root;
}
void clear() {
root = nullptr;
}
};
unittest {
default_random_engine gen;
auto generate = [&]() {
red_black_tree<double> rbtree;
deque<double> dec;
REP (iteration, 100) {
double value = uniform_real_distribution<double>()(gen);
if (bernoulli_distribution(0.5)(gen)) {
rbtree.push_back(value);
dec.push_back(value);
} else {
rbtree.push_front(value);
dec.push_front(value);
}
}
return make_pair( move(rbtree), dec );
};
REP (iteration, 1000) {
red_black_tree<double> rbtree;
deque<double> dec;
tie(rbtree, dec) = generate();
REP (iteration, 100) {
assert (rbtree.size() == dec.size());
int k = uniform_int_distribution<int>(0, rbtree.size())(gen);
int i = rbtree.empty() ? -1 : uniform_int_distribution<int>(0, rbtree.size() - 1)(gen);
double value = uniform_real_distribution<double>()(gen);
switch (uniform_int_distribution<int>(0, 8)(gen)) {
case 0: // merge
{
red_black_tree<double> rbtree2;
deque<double> dec2;
tie(rbtree2, dec2) = generate();
rbtree = red_black_tree<double>::merge(rbtree, rbtree2);
copy(ALL(dec2), back_inserter(dec));
}
break;
case 1: // split
if (bernoulli_distribution(0.5)(gen)) {
rbtree = rbtree.split(k).first;
dec.erase(dec.begin() + k, dec.end());
} else {
rbtree = rbtree.split(k).second;
dec.erase(dec.begin(), dec.begin() + k);
}
break;
case 2: // insert
rbtree.insert(k, value);
dec.push_back(value);
rotate(dec.begin() + k, dec.begin() + (dec.size() - 1), dec.end());
break;
case 3: // erase
if (not rbtree.empty()) {
rbtree.erase(i);
rotate(dec.begin() + i, dec.begin() + (i + 1), dec.end());
dec.pop_back();
}
break;
case 4: // push_back
rbtree.push_back(value);
dec.push_back(value);
break;
case 5: // push_front
rbtree.push_front(value);
dec.push_front(value);
break;
case 6: // pop_back
if (not rbtree.empty()) {
rbtree.pop_front();
dec.pop_front();
}
break;
case 7: // pop_front
if (not rbtree.empty()) {
rbtree.pop_back();
dec.pop_back();
}
break;
case 8: // set
if (not rbtree.empty()) {
rbtree.set(i, value);
dec[i] = value;
}
break;
default:
assert (false);
}
REP (i, rbtree.size()) {
assert (rbtree.get(i) == dec[i]);
}
}
}
}
#line 1 "old/red-black-tree.inc.cpp"
/**
* @note almost all operations are O(log N)
*/
template <class T>
class red_black_tree {
enum color_t { BLACK, RED };
struct node_t {
bool is_leaf;
union {
T data;
struct {
color_t m_color;
int m_rank;
int m_size;
node_t *left;
node_t *right;
};
};
node_t() = default;
node_t(T const & a_data)
: is_leaf(true)
, data(a_data) {
}
node_t(node_t *l, node_t *r, color_t c) // non-leaf node
: is_leaf(false)
, m_color(c)
, m_rank(max(rank(l) + (color(l) == BLACK),
rank(r) + (color(r) == BLACK)))
, m_size(size(l) + size(r))
, left(l)
, right(r) {
}
};
struct node_deleter {
void operator () (node_t *t) const {
assert (t != nullptr);
if (not t->is_leaf) {
(*this)(t->right);
(*this)(t->left);
}
delete t;
}
};
static inline color_t color(node_t const *t) {
return t->is_leaf ? BLACK : t->m_color;
}
static inline int rank(node_t const *t) {
return t->is_leaf ? 0 : t->m_rank;
}
static inline int size(node_t const *t) {
return t->is_leaf ? 1 : t->m_size;
}
/**
* @note trees a, b are consumed (at set_left()/set_right())
*/
static node_t *merge(node_t *a, node_t *b) {
if (a == nullptr) return b;
if (b == nullptr) return a;
node_t *c = merge_relax(a, b);
c->m_color = BLACK;
return c;
}
/*
* @note the root of returned tree may violates the color constraint
*/
static node_t *merge_relax(node_t *a, node_t *b) {
if (rank(a) < rank(b)) {
assert (not b->is_leaf);
return set_left(b, merge_relax(a, b->left));
} else if (rank(a) > rank(b)) {
assert (not a->is_leaf);
return set_right(a, merge_relax(a->right, b));
} else {
a->m_color = BLACK;
b->m_color = BLACK;
return new node_t(a, b, RED);
}
}
static node_t *set_left(node_t *b, node_t *c) {
if (b->m_color == BLACK and c->m_color == RED and color(c->left) == RED) {
if (color(b->right) == BLACK) {
*b = node_t(c->right, b->right, RED);
*c = node_t(c->left, b, BLACK);
swap(b, c);
} else {
b->right->m_color = BLACK;
c->m_color = BLACK;
*b = node_t(c, b->right, RED);
}
} else {
*b = node_t(c, b->right, b->m_color);
}
return b;
}
static node_t *set_right(node_t *a, node_t *c) {
if (a->m_color == BLACK and c->m_color == RED and color(c->right) == RED) {
if (color(a->left) == BLACK) {
*a = node_t(a->left, c->left, RED);
*c = node_t(a, c->right, BLACK);
swap(a, c);
} else {
a->left->m_color = BLACK;
c->m_color = BLACK;
*a = node_t(a->left, c, RED);
}
} else {
*a = node_t(a->left, c, a->m_color);
}
return a;
}
/**
* @note tree a is consumed (at explicit delete and merge())
*/
static pair<node_t *, node_t *> split(node_t *a, int k) {
if (k == 0) {
return make_pair( nullptr, a );
}
assert (a != nullptr);
if (k == size(a)) {
return make_pair( a, nullptr );
}
assert (not a->is_leaf);
node_t *a_left = a->left;
node_t *a_right = a->right;
delete a;
if (k < size(a_left)) {
node_t *l, *r; tie(l, r) = split(a_left, k);
return make_pair( l, merge(r, a_right) );
} else if (k > size(a_left)) {
node_t *l, *r; tie(l, r) = split(a_right, k - size(a_left));
return make_pair( merge(a_left, l), r );
} else {
return make_pair( a_left, a_right );
}
}
/**
* @tparam (A, B) = (node_t const *, T const &), (node_t *, T &)
*/
template <class A, class B>
static B get_generic(A a, int i) {
if (a->is_leaf) {
assert (i == 0);
return a->data;
} else {
if (i < size(a->left)) {
return get_generic<A, B>(a->left, i);
} else {
return get_generic<A, B>(a->right, i - size(a->left));
}
}
}
private:
unique_ptr<node_t, node_deleter> root;
public:
red_black_tree<T>() = default;
red_black_tree<T>(node_t *a_root) : root(a_root) {}
static red_black_tree<T> merge(red_black_tree<T> & l, red_black_tree<T> & r) {
node_t *a = l.root.release();
node_t *b = r.root.release();
if (a == nullptr) return red_black_tree<T>(b);
if (b == nullptr) return red_black_tree<T>(a);
return red_black_tree<T>(merge(a, b));
}
pair<red_black_tree<T>, red_black_tree<T> > split(int k) {
assert (0 <= k and k <= size());
node_t *l, *r; tie(l, r) = split(root.release(), k);
return make_pair( red_black_tree<T>(l), red_black_tree<T>(r) );
}
void insert(int i, T const & data) {
assert (0 <= i and i <= size());
if (empty()) {
root.reset(new node_t(data));
return;
} else {
node_t *l, *r; tie(l, r) = split(root.release(), i);
root.reset( merge(merge(l, new node_t(data)), r) );
}
}
void erase(int i) {
assert (0 <= i and i < size());
node_t *l, *r; tie(l, r) = split(root.release(), i + 1);
node_t *m; tie(l, m) = split(l, i);
node_deleter()(m);
root.reset( merge(l, r) );
}
void set(int i, T const & data) {
assert (0 <= i and i < size());
get_generic<node_t *, T &>(root.get(), i) = data;
}
T const & get(int i) const {
assert (0 <= i and i < size());
return get_generic<node_t const *, T const &>(root.get(), i);
}
void push_back(T const & data) {
root.reset( merge(root.release(), new node_t(data)) );
}
void push_front(T const & data) {
root.reset( merge(new node_t(data), root.release()) );
}
void pop_back() {
int k = size() - 1;
auto lr = split(root.release(), k);
root.reset(lr.first);
node_deleter()(lr.second);
}
void pop_front() {
auto lr = split(root.release(), 1);
node_deleter()(lr.first);
root.reset(lr.second);
}
int size() const {
return root ? size(root.get()) : 0;
}
bool empty() const {
return not root;
}
void clear() {
root = nullptr;
}
};
unittest {
default_random_engine gen;
auto generate = [&]() {
red_black_tree<double> rbtree;
deque<double> dec;
REP (iteration, 100) {
double value = uniform_real_distribution<double>()(gen);
if (bernoulli_distribution(0.5)(gen)) {
rbtree.push_back(value);
dec.push_back(value);
} else {
rbtree.push_front(value);
dec.push_front(value);
}
}
return make_pair( move(rbtree), dec );
};
REP (iteration, 1000) {
red_black_tree<double> rbtree;
deque<double> dec;
tie(rbtree, dec) = generate();
REP (iteration, 100) {
assert (rbtree.size() == dec.size());
int k = uniform_int_distribution<int>(0, rbtree.size())(gen);
int i = rbtree.empty() ? -1 : uniform_int_distribution<int>(0, rbtree.size() - 1)(gen);
double value = uniform_real_distribution<double>()(gen);
switch (uniform_int_distribution<int>(0, 8)(gen)) {
case 0: // merge
{
red_black_tree<double> rbtree2;
deque<double> dec2;
tie(rbtree2, dec2) = generate();
rbtree = red_black_tree<double>::merge(rbtree, rbtree2);
copy(ALL(dec2), back_inserter(dec));
}
break;
case 1: // split
if (bernoulli_distribution(0.5)(gen)) {
rbtree = rbtree.split(k).first;
dec.erase(dec.begin() + k, dec.end());
} else {
rbtree = rbtree.split(k).second;
dec.erase(dec.begin(), dec.begin() + k);
}
break;
case 2: // insert
rbtree.insert(k, value);
dec.push_back(value);
rotate(dec.begin() + k, dec.begin() + (dec.size() - 1), dec.end());
break;
case 3: // erase
if (not rbtree.empty()) {
rbtree.erase(i);
rotate(dec.begin() + i, dec.begin() + (i + 1), dec.end());
dec.pop_back();
}
break;
case 4: // push_back
rbtree.push_back(value);
dec.push_back(value);
break;
case 5: // push_front
rbtree.push_front(value);
dec.push_front(value);
break;
case 6: // pop_back
if (not rbtree.empty()) {
rbtree.pop_front();
dec.pop_front();
}
break;
case 7: // pop_front
if (not rbtree.empty()) {
rbtree.pop_back();
dec.pop_back();
}
break;
case 8: // set
if (not rbtree.empty()) {
rbtree.set(i, value);
dec[i] = value;
}
break;
default:
assert (false);
}
REP (i, rbtree.size()) {
assert (rbtree.get(i) == dec[i]);
}
}
}
}