/// Randomized Treap (Cartesian Tree)
///   Store x (key), simulate y (priority)
///   Store value
///   Maintain size of subtree
///   total: sum of values in subtree
/// Base Functions
///   tSplit: split into <x and >=x
///   tMerge: merge trees l and r if {keys of l} <= {keys of r}
/// Map Interface (Multimap)
///   tInsert: add (x, value) pair into map
///   tFind: return value for given key x
///   tAssign: assign value for given key x, assume at least one exists
///   tRemove: erase all keys x from map
/// Debugging
///   tOutput: print bracket structure of tree
/// Example Usage
///   Add 10^7 elements
///   Find 10^7 elements
///   Split into two parts, check sizes
///   Cut middle part, check total
///   Reassign an element in the middle
///   Cut middle part, check total again
///   Remove 10^7 elements
#include <bits/stdc++.h>
using namespace std;

auto gen = mt19937 (time (0));
using uniform = uniform_int_distribution <int>;

struct Node;
using PNode = Node *;
int getSize (PNode t);
using Num = long long;
Num getTotal (PNode t);
struct Node
{
	int x;
	Num value;
	Num total;
	int size;
	PNode left;
	PNode right;
	
	void recalc ()
	{
		size = 1 + getSize (left) + getSize (right);
		total = value + getTotal (left) + getTotal (right);
	}

	Node (int x_, Num value_)
	{
		x = x_;
		value = value_;
		total = value_;
		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;
}

Num getTotal (PNode t)
{
	return t == nullptr ? Num (0) : t -> total;
}

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 (uniform (0, l -> size + r -> size - 1) (gen) < l -> size)
	{
		l -> right = tMerge (l -> right, r);
		l -> recalc ();
		return l;
	}
	else
	{
		r -> left = tMerge (l, r -> left);
		r -> recalc ();
		return r;
	}
}

PNode tInsert (PNode t, int x, Num value)
{
	auto v = new Node (x, value);
	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 -> value <<
		    '|' << t -> size << '"' << t -> total;
		tOutput (t -> right, false);
		cout << ')';
	}
	if (doEndl) cout << '.' << endl;
}

Num tFind (PNode t, int x)
{
	if (t == nullptr) return Num (-1);
	if (t -> x == x) return t -> value;
	if (t -> x < x) return tFind (t -> right, x);
	else return tFind (t -> left, x);
}

PNode tAssign (PNode t, int x, Num value)
{
	auto p = tSplit (t, x);
	auto q = tSplit (p.second, x + 1);
	q.first -> value = value;
	q.first -> recalc ();
	p.second = tMerge (q.first, q.second);
	return tMerge (p.first, p.second);
}

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, (x * 1LL * x) % 17);
		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 << "sizes: " << getSize (p.first) << " " <<
		    getSize (p.second) << endl;
		root = tMerge (p.first, p.second);
	}

	{
		auto p = tSplit (root, 3333333);
		auto q = tSplit (p.second, 6666666);
		cout << "total: " << getTotal (q.first) << endl;
		p.second = tMerge (q.first, q.second);
		root = tMerge (p.first, p.second);
	}

	{
		root = tAssign (root, 5000000, 10000);
	}

	{
		auto p = tSplit (root, 3333333);
		auto q = tSplit (p.second, 6666666);
		cout << "total: " << getTotal (q.first) << endl;
		p.second = tMerge (q.first, q.second);
		root = tMerge (p.first, p.second);
	}

	if (false)
	for (int x = 1; x <= limit; x++)
	{
		root = tRemove (root, x * 2);
		if (limit - x <= 10) tOutput (root);
	}
	
	return 0;
}
