// Подробные комментарии добавлю позже.
#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif // LOCAL
#include <bits/stdc++.h>
using namespace std;

mt19937 rng;

struct node
{
    int x, y;

    int l, r;

    int cnt;

// Относительно вероятные одиночные совпадения <<игреков>>, если в дереве много сотен тысяч вершин.
// Из-за этого могут возникнуть проблемы с однозначностью дерева. Может иметь смысл сделать <<игреки>>
// 64-битными числами и использовать mt19937_64 вместо mt19937.
    node (const int x_) : x(x_), y(rng()), l(-1), r(-1), cnt(1) {}
};

struct treap_manager
{
    vector<node> v;

    int create_vertex (const int x)
    {
        const int ans = int(v.size());
        v.emplace_back(x);
        return ans;
    }

    int cnt (const int t)
    {
        return t == -1 ? 0 : v[t].cnt;
    }

    void update (const int t)
    {
        if (t != -1)
            v[t].cnt = cnt(v[t].l) + 1 + cnt(v[t].r);
    }

    /// <x, >=x
    pair<int, int> split (const int t, const int x)
    {
        if (t == -1)
            return {-1, -1};

        if (v[t].x < x)
        {
            auto [l, r] = split(v[t].r, x);
            v[t].r = l;
//            v[t].cnt -= v[r].cnt;
            update(t);
            return {t, r};
        }
        else
        {
            auto [l, r] = split(v[t].l, x);
            v[t].l = r;
//            v[t].cnt -= v[l].cnt;
            update(t);
            return {l, t};
        }
    }

    int merge (const int l, const int r)
    {
        if (l == -1)
            return r;
        if (r == -1)
            return l;

        const int res_cnt = v[l].cnt + v[r].cnt;

        if (v[l].y < v[r].y)
        {
            v[r].l = merge(l, v[r].l);
//            v[r].cnt = res_cnt;
            update(r);
            return r;
        }
        else
        {
            v[l].r = merge(v[l].r, r);
//            v[l].cnt = res_cnt;
            update(l);
            return l;
        }
    }

    int del (const int root, const int x)
    {
        auto [l, tmp] = split(root, x);
        auto [m, r] = split(tmp, x + 1);
        /// m -> дерево из x
        return merge(l, r);
    }

    int ins (const int root, const int x)
    {
        auto [l, r] = split(root, x);
        const int m = create_vertex(x);
        return merge(merge(l, m), r);
    }

    bool find (const int root, const int x)
    {
        if (root == -1)
            return false;

        if (v[root].x == x)
            return true;

        if (x < v[root].x)
            return find(v[root].l, x);
        return find(v[root].r, x);
    }

    int kth_smallest (const int root, const int k)
    {
        assert(root != -1);
        assert(0 <= k && k < v[root].cnt);

        const int l = v[root].l;
        if (k == cnt(l))
            return v[root].x;
        else if (k < cnt(l))
            return kth_smallest(v[root].l, k);
        else
            /// k >= v[l].cnt + 1;
            return kth_smallest(v[root].r, k - cnt(l) - 1);
    }

    void check_cnt (const int root)
    {
        if (root == -1)
            return;

        assert(cnt(root) == cnt(v[root].l) + 1 + cnt(v[root].r));
        check_cnt(v[root].l);
        check_cnt(v[root].r);
    }
};

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    treap_manager info;
    int root = -1;

    int n;
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        int type, k;
        cin >> type >> k;

        if (type == +1)
            root = info.ins(root, k);
        else if (type == 0)
        {
            const int real_k = info.cnt(root) - k;
            cout << info.kth_smallest(root, real_k) << '\n';
        }
        else
        {
            assert(type == -1);
            root = info.del(root, k);
        }
    }
}
