The Treap is a data structure that maintains an array of numbers by maintaining a binary tree.

Specifically, a random priority is generated for each . In the binary tree, each node stores a pair . The binary tree satisfies that the in-order traversal order of the nodes matches their order in the array, and the priority of each node is lower than the priority of its parent. In other words, the binary tree is a Cartesian Tree with respect to .

This costs of space of .

Lemma

Let denote the depth of the -th node in the binary tree, then

Split

Split splits a Treap of into two Treaps of and , respectively, in expected time and expected space.

Algorithm

  • If the size of the left sub-Treap of the root is greater than or equal to , the whole right sub-Treap should be in the second Treap. Split the left sub-Treap recursively.

  • Otherwise, 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 y_combinator([&](auto &&self, Node *o, int k) -> std::pair<Node *, Node *> {
		if (!o) {
			return {nullptr, nullptr};
		}
 
		if (k <= size(o->lch)) {
			auto [x, y] = self(o->lch, k);
			o->lch = y;
			o->siz = size(o->lch) + 1 + size(o->rch);
			return {x, o};
		} else {
			auto [x, y] = self(o->rch, k - size(o->lch) - 1);
			o->rch = x;
			o->siz = size(o->lch) + 1 + size(o->rch);
			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 be the root of the first Treap, be the root of the second Treap.

  • If the priority of is higher than the priority of , 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 y_combinator([&](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 = size(x->lch) + 1 + size(x->rch);
			return x;
		} else {
			y->lch = self(x, y->lch);
			y->siz = size(y->lch) + 1 + size(y->rch);
			return y;
		}
	})(x, y);
}