#include using namespace std; mt19937 rng_priority; struct node { int l, r; int y; int cnt; node () : y(rng_priority()), l(-1), r(-1), cnt(1) {} }; struct treap_manager { vector pool; int add_node(const int x) { const int ans = int(pool.size()); pool.push_back(node(x)); return ans; } int subtree (const int v) { /// if (v == -1) /// return 0; /// else /// return pool[v].cnt; return v == -1 ? 0 : pool[v].cnt; } void recalc(const int v) { if (v != -1) pool[v].cnt = subtree(pool[v].l) + 1 + subtree(pool[v].r); } int merge(int l, int m, int r) { return merge(merge(l, m), r); } pair split (const int t, const int xs) { if (t == -1) return pair(-1, -1); int l, r; if (pool[t].x < xs) { /// Так МОЖНО написать, но не нужно. // const int mem = pool[t].r; // pool[t].r = -1; // tie(l, r) = split(mem, x); // pool[t].r = l; tie(l, r) = split(pool[t].r, xs); /// Поддеревья l и r --- всё хорошо (cnt-шки посчитаны правильно). pool[t].r = l; /// Слишком умные студенты :) pool[t].cnt -= subtree(r); return pair(t, r); } else { // pool[t].x >= x; tie(l, r) = split(pool[t].l, xs); pool[t].l = r; pool[t].cnt -= subtree(l); return pair(l, t); } } int merge (int l, int r) { if (l == -1) return r; if (r == -1) return l; const int total_size = subtree(l) + subtree(r); if (pool[l].y > pool[r].y) { const int sr = subtree(r); pool[l].r = merge(pool[l].r, r); /// А вот это работает! pool[l].cnt += sr; // pool[l].cnt = total_size; return l; } else { const int sl = subtree(l); pool[r].l = merge(l, pool[r].l); /// А вот это работает! pool[r].cnt += sl; // pool[r].cnt = total_size; return r; } } /// добавить вершину ver в дерево tree int insert_node (const int tree, const int ver) { int l, r; tie(l, r) = split(tree, pool[ver].x); return merge(l, ver, r); } int insert_key (const int tree, const int x) { const int ver = add_node(x); return insert_node(tree, ver); } /// возвращает идентификатор дерева после удаления ключа x int remove_key (const int tree, const int x) { int l, m, r; tie(l, m) = split(tree, x); /// в l все ключи < x /// в m все ключи >= x tie(m, r) = split(m, x + 1); /// в m теперь ключ x return merge(l, r); } /// в 0-индексации, то есть 0 <= k < subtree(root); int get_kth_key (const int root, const int k) { assert(0 <= k && k < subtree(root)); if (k == subtree(pool[root].l)) return pool[root].x; if (k < subtree(pool[root].l)) return get_kth_key(pool[root].l, k); /// k >= subtree(pool[root].l) + 1; return get_kth_key(pool[root].r, k - subtree(pool[root].l) - 1); } }; void solve(istream &cin, ostream &cout) { treap_manager treap; int root = -1; int n; cin >> n; for (int i = 0; i < n; i++) { int t, k; cin >> t >> k; if (t == +1) root = treap.insert_key(root, k); else if (t == -1) root = treap.remove_key(root, k); else if (t == 0) { k--; /// [0, subtree(root)) <-> [0, subtree(root)), развёрнутое cout << treap.get_kth_key(root, treap.subtree(root) - 1 - k) << "\n"; } } } int main() { // ifstream fin("input.txt"); // ofstream fout("output.txt"); // solve(fin, fout); solve(cin, cout); }