The Treap is a data structure that maintains a sequence of numbers by maintaining a randomized Cartesian Tree.
Specifically, a random priority is generated independently and identically for each . The Cartesian Tree is built based on , and each node stores both and .
This requires space.
Lemma
Let denote the depth of the -th node in the Cartesian Tree, then
Proof
Let be if is an ancestor of , excluding itself, and otherwise, then
If , since is an ancestor of iff
it follows that
Symmetrically, it is easy to prove that, if ,
Therefore,
Split
Split splits a Treap of into two Treaps of and , respectively, in expected time and expected space.
Algorithm
-
If is less than or equal the size of the left sub-Treap of the root, the root and the whole right sub-Treap should be in the second Treap. Split the left sub-Treap recursively.
-
Otherwise, the root and the whole left sub-Treap should be in the first Treap. Split the right sub-Treap recursively.
This algorithm solves the problem in expected time and expected space.
std::pair<Node *, Node *> split(Node *o, int k) {
return [&](this auto &&self, Node *o, int k) -> std::pair<Node *, Node *> {
if (!o) {
return {nullptr, nullptr};
}
if (k <= (o->lch ? o->lch->siz : 0)) {
auto [x, y] = self(o->lch, k);
o->lch = y;
o->siz = 1 + (o->lch ? o->lch->siz : 0) + (o->rch ? o->rch->siz : 0);
return {x, o};
} else {
auto [x, y] = self(o->rch, k - (o->lch ? o->lch->siz : 0) - 1);
o->rch = x;
o->siz = 1 + (o->lch ? o->lch->siz : 0) + (o->rch ? o->rch->siz : 0);
return {o, y};
}
} (o, k);
}Merge
Merge merges two Treaps of and , respectively, into a single Treap of in expected time and expected space.
Algorithm
Let denote the root of the first Treap, denote the root of the second Treap.
- If , should be the root of the merged Treap. Merge the right sub-Treap of with the second Treap recursively.
- Otherwise, should be the root of the merged Treap. Merge the first Treap with the left sub-Treap of recursively.
This algorithm solves the problem in expected time and expected space.
Node *merge(Node *x, Node *y) {
return [&](this auto &&self, Node *x, Node *y) -> Node * {
if (!x) {
return y;
}
if (!y) {
return x;
}
if (x->prio > y->prio) {
x->rch = self(x->rch, y);
x->siz = 1 + (x->lch ? x->lch->siz : 0) + (x->rch ? x->rch->siz : 0);
return x;
} else {
y->lch = self(x, y->lch);
y->siz = 1 + (y->lch ? y->lch->siz : 0) + (y->rch ? y->rch->siz : 0);
return y;
}
} (x, y);
}