#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ull = unsigned long long;

mt19937 mt(736);

// план изменений:
// были пары (x, y)
// добавили siz
// можно избавиться от y (условия на кучу)
// получим randomized binary search tree
// split_by_size -> можно избавиться от x (условия на дерево поиска, т.е. неравенство между x)


// добавлять/удалять числа из множества, проверять на наличие
// std::set<int>

// будем делать merge/split, при помощи них реализуем insert/erase


// если не хотим использовать new/delete
// shared_ptr, weak_ptr, unique_ptr
class treap
{
	struct node
	{
		using nodeptr = node *;

		int x, siz;
		nodeptr l, r;
		bool rev;

		explicit node(int x, nodeptr l = nullptr, nodeptr r = nullptr) : x(x), l(l), r(r), siz(), rev(false)
		{
			upd(this);
		}

		~node()
		{
			delete l;
			delete r;
		}
	};

	using nodeptr = node::nodeptr;

	static int get_siz(nodeptr h)
	{
		return h == nullptr ? 0 : h->siz;
	}


	static void reverse(nodeptr h)
	{
		if (h != nullptr)
			h->rev = !h->rev;
	}


	static void push(nodeptr h)
	{
		if (h != nullptr && h->rev)
		{
			reverse(h->l);
			reverse(h->r);

			swap(h->l, h->r);

			h->rev = false;
		}
	}


	static void upd(nodeptr h)
	{
		if (h == nullptr)
			return;

		h->siz = get_siz(h->l) + 1 + get_siz(h->r);
	}

	// верим, что все ключи le < ключей ri, иначе не работает
	// надо поддержать свойство кучи на y (когда есть явные y)
	static nodeptr merge(nodeptr le, nodeptr ri)
	{
		if (le == nullptr)
			return ri;
		if (ri == nullptr)
			return le;

		push(le);
		push(ri);

		//if (le->y < ri->y) // явные y
		if (uniform_int_distribution<int>{0, get_siz(le) + get_siz(ri) - 1}(mt) < get_siz(le)) // неявные
			// эта ветка выполняется с вероятностью size(le) / (size(le) + size(ri))
		{
			le->r = merge(le->r, ri);

			upd(le);

			return le;
		}
		else
			// эта ветка выполняется с вероятностью size(ri) / (size(le) + size(ri))
		{
			ri->l = merge(le, ri->l);

			upd(ri);

			return ri;
		}
	}


	// дерево le = все ключи < x
	// дерево ri = все ключи >= x
	static void split(nodeptr h, nodeptr &le, nodeptr &ri, int x)
	{
		if (h == nullptr)
		{
			le = ri = nullptr;

			return;
		}

		push(h);

		if (h->x < x)
		{
			le = h;

			split(h->r, le->r, ri, x);

			// le = h, le->r = подмножество вершин в поддереве h->r, а они имебт правильное неравенство с вершиной h
		}
		else
		{
			ri = h;

			split(h->l, le, ri->l, x);
		}

		upd(le);
		upd(ri);
	}


	// дерево le резмера min(k, size(h))
	// дерево ri -- все оставшееся
	static void split_by_size(nodeptr h, nodeptr &le, nodeptr &ri, int k)
	{
		if (h == nullptr)
		{
			le = ri = nullptr;

			return;
		}

		push(h);

		if (get_siz(h->l) < k)
		{
			le = h;

			split_by_size(h->r, le->r, ri, k - get_siz(h->l) - 1);
		}
		else
		{
			ri = h;

			split_by_size(h->l, le, ri->l, k);
		}

		upd(le);
		upd(ri);
	}


	nodeptr root = nullptr;

public:
	~treap()
	{
		delete root;
	}


	[[nodiscard]] int size() const
	{
		return get_siz(root);
	}


	void erase(int x)
	{
		nodeptr le, mi, ri, tmp;

		split(root, le, tmp, x);

		// le : < x
		// tmp: >= x

		split(tmp, mi, ri, x + 1);

		// le : < x
		// mi : = x
		// ri : > x

		delete mi;

		root = merge(le, ri);
	}


	int count(int x)
	{
		nodeptr le, mi, ri, tmp;

		split(root, le, tmp, x);

		// le : < x
		// tmp: >= x

		split(tmp, mi, ri, x + 1);

		// le : < x
		// mi : = x
		// ri : > x

		int ans = mi == nullptr ? 0 : 1;

		root = merge(le, merge(mi, ri));

		return ans;
	}


	void insert(int x)
	{
		nodeptr le, ri;

		split(root, le, ri, x);

		root = merge(le, merge(new node(x), ri));
	}


	int kth_element(int k)
	{
		nodeptr le, mi, ri, tmp;

		split_by_size(root, le, tmp, k);
		split_by_size(tmp, mi, ri, 1);

		assert(mi != nullptr);

		int ans = mi->x;

		root = merge(le, merge(mi, ri));

		return ans;
	}

	void reverse() // O(1)
	{
		reverse(root);
	}
};


void solve(istream &cin = std::cin, ostream &cout = std::cout)
{
	treap tr;
	set<int> st;

	uniform_int_distribution<int> uid(1, 10);

	for (int i = 0; i < (int)1e5; i++)
	{
		if (uid(mt) % 2)
		{
			auto x = uid(mt);

			assert(tr.count(x) == st.count(x));

			if (tr.count(x) == 0)
			{
				tr.insert(x);
				st.insert(x);
			}
		}
		else
		{
			auto x = uid(mt);

			assert(tr.count(x) == st.count(x));

			if (tr.count(x) == 1)
			{
				tr.erase(x);
				st.erase(x);
			}
		}

		for (int j = 1; j <= 10; j++)
			assert(tr.count(j) == st.count(j));
		assert(tr.size() == st.size());

		if (!st.empty())
		{
			tr.reverse();
			assert(tr.kth_element(0) == *st.rbegin());
			tr.reverse();
		}

		cout << i << endl;
	}
}


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

	cout << fixed;

#ifdef LOCAL
	auto st = clock();

	ifstream fin("../input.txt");

	do
	{
		solve(fin);

		cout << "===" << endl;

		string str;
		while (getline(fin, str) && str != string(max(1, (int) str.size()), '='));
	} while (fin);

	cout << setprecision(6) << "clock: " << double(clock() - st) / CLOCKS_PER_SEC << endl;
#else
	solve();
#endif

	return 0;
}
