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

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);
}