/// Treap (Cartesian Tree)
///   Store x (key) and y (priority)
///   Maintain size of subtree
/// Base Functions
///   tSplit: split into <x and >=x
///   tMerge: merge trees l and r if {keys of l} <= {keys of r}
/// Set Interface (Multiset)
///   tInsert: add x into set
///   tFind: test if x is in set
///   tRemove: erase all x from set
/// Debugging
///   tOutput: print bracket structure of tree
/// Example Usage
///   Add 10^7 elements
///   Find 10^7 elements
///   Split into two parts, check sizes
///   Remove 10^7 elements
#include <bits/stdc++.h>
using namespace std;

auto gen = mt19937 (time (0));
auto uniform = uniform_int_distribution <int> (0, int (1E9));

struct Node;
using PNode = Node *;
int getSize (PNode t);
struct Node
{
	int x;
	int y;
	int size;
	PNode left;
	PNode right;
	
	void recalc ()
	{
		size = 1 + getSize (left) + getSize (right);
	}

	Node (int x_)
	{
		x = x_;
		y = uniform (gen);
		size = 1;
		left = nullptr;
		right = nullptr;
	}

	~Node ()
	{
		if (left != nullptr) delete left;
		if (right != nullptr) delete right;
	}
};

int getSize (PNode t)
{
	return t == nullptr ? 0 : t -> size;
}

pair <PNode, PNode> tSplit (PNode t, int x)
{
	if (t == nullptr) return {nullptr, nullptr};
	if (t -> x >= x)
	{
		auto p = tSplit (t -> left, x);
		t -> left = p.second;
		t -> recalc ();
		return {p.first, t};
	}
	else
	{
		auto p = tSplit (t -> right, x);
		t -> right = p.first;
		t -> recalc ();
		return {t, p.second};
	}
}

PNode tMerge (PNode l, PNode r)
{
	if (l == nullptr) return r;
	if (r == nullptr) return l;
	if (l -> y < r -> y)
	{
		r -> left = tMerge (l, r -> left);
		r -> recalc ();
		return r;
	}
	else
	{
		l -> right = tMerge (l -> right, r);
		l -> recalc ();
		return l;
	}
}

PNode tInsert (PNode t, int x)
{
	auto v = new Node (x);
	auto p = tSplit (t, x);
	auto half = tMerge (p.first, v);
	return tMerge (half, p.second);
}

void tOutput (PNode t, bool doEndl = true)
{
	if (t != nullptr)
	{
		cout << '(';
		tOutput (t -> left, false);
		cout << t -> x << '|' << t -> size;
		tOutput (t -> right, false);
		cout << ')';
	}
	if (doEndl) cout << '.' << endl;
}

bool tFind (PNode t, int x)
{
	if (t == nullptr) return false;
	if (t -> x == x) return true;
	if (t -> x < x) return tFind (t -> right, x);
	else return tFind (t -> left, x);
}

PNode tRemove (PNode t, int x)
{
	auto p = tSplit (t, x);
	auto q = tSplit (p.second, x + 1);
	delete q.first;
	return tMerge (p.first, q.second);
}

int main ()
{
/*
	Node u;
	u.left; u.right;
	PNode v;
	(*v).left; (*v).right;
	v -> left; v -> right;
*/
	int const limit = int (1E7);
	PNode root = nullptr;
	
	for (int x = 1; x <= limit; x++)
	{
		root = tInsert (root, x * 2);
		if (x <= 10) tOutput (root);
	}
	
	for (int x = 1; x <= limit; x++)
	{
		auto res = tFind (root, x);
		if (x <= 10) cout << x << ' ' << res << endl;
	}
	
	{
		auto p = tSplit (root, limit * 2 - 5);
		cout << getSize (p.first) << " " <<
		    getSize (p.second) << endl;
		root = tMerge (p.first, p.second);
	}
	
	for (int x = 1; x <= limit; x++)
	{
		root = tRemove (root, x * 2);
		if (limit - x <= 10) tOutput (root);
	}
	
	return 0;
}
