#include <iostream>
#include <fstream>
#include <set>
#include <algorithm>
#include <cmath>
#include <limits>
#include <ctime>
#include <cstdio>
#include <cstdlib>
using namespace std;
//std::ifstream in("algsort.in");
//std::ofstream out("algsort.out");
std::ifstream hin("hashuri.in");
std::ofstream hout("hashuri.out");;
class RBT
{
public:
RBT(){init();};
const bool RED = 1,BLACK = 0;
struct node
{
int key;
unsigned color:1;
node* left, *right,*parent;
node(int k,bool c, node* lt, node* rt,node* pt):key{k},color{c},left{lt},right{rt},parent{pt}{};
};
node *root ,* nil;
void init()
{
root = nullptr;
nil = new node(0,BLACK,nullptr,nullptr,nullptr);
}
bool search(int key,node* root)
{
if(root == nullptr || root == nil)
return false;
else if(key <root->key)
return search(key,root->left);
else if(key>root->key)
return search(key,root->right);
else
return true;
}
void insert(int key,node* &root,node* parent)
{
if(root == nullptr)
{
root = new node(key,BLACK,nil,nil,parent);
insert_case1(root);
}
else if( root == nil)
{
root = new node(key,RED,nil,nil,parent);
insert_case1(root);
}
else if( key <= root->key)
insert(key,root->left,root);
else if( key > root->key)
insert(key,root->right,root);
}
node *grandparent(struct node *n)
{
if ((n != nullptr) && (n->parent != nullptr))
return n->parent->parent;
return nullptr;
}
node *uncle(struct node *n)//unchiul nodului n
{
node *g = grandparent(n);
if (g == nullptr)
return nullptr; // No grandparent means no uncle
if (n->parent == g->left)
return g->right;
else
return g->left;
}
void leftRotate(node* &T,node * x)
{
node * y = x->right;
x->right = y->left;
if(y->left != nil)
y->left->parent = x;
y->parent = x->parent;
if(x->parent == nullptr)
T = y;
else
{
if(x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
}
y->left =x;
x->parent =y;
}
void rightRotate(node* &T,node* y) //rotim la dreapta
{
node* x = y->left;
y->left = x->right;
if(x->right != nil)
x->right->parent = y;
x->parent = y->parent;
if(y->parent == nullptr)
T = x;
else
{
if(y->parent->left == y)
y->parent->left = x;
else
y->parent->right = x;
}
x->right = y;
y->parent = x;
}
void insert_case1(node *n) //caz radacina deci doar o coloram negru
{
if (n->parent == nullptr)
n->color = BLACK;
else
insert_case2(n);
}
void insert_case2(node *n)//caz cand
{
if (n->parent->color == BLACK)
return; /* Tree is still valid */
else
insert_case3(n);//altfel
}
void insert_case3(node *n)
{
node *u = uncle(n), *g;
if ((u != nullptr) && (u->color == RED))
{
n->parent->color = BLACK;
u->color = BLACK;
g = grandparent(n);
g->color = RED;
insert_case1(g);
}
else
insert_case4(n);
}
void insert_case4(node *n)
{
node *g = grandparent(n);
if ((n == n->parent->right) && (n->parent == g->left))
{
leftRotate(root,n->parent);
n = n->left;
}
else if ((n == n->parent->left) && (n->parent == g->right))
{
rightRotate(root,n->parent);
n = n->right;
}
insert_case5(n);
}
void insert_case5(node *n)
{
node *g = grandparent(n);
n->parent->color = BLACK;
g->color = RED;
if (n == n->parent->left)
rightRotate(root,g);
else
leftRotate(root,g);
}
node *sibling(node *n)
{
if ((n == nullptr) || (n->parent == nullptr))
return nullptr;
if (n == n->parent->left)
return n->parent->right;
else
return n->parent->left;
}
node* getMin(node* root)
{
if(root == nullptr)
return root;
return ( root->left == nil ) ? root : getMin( root->left );
}
node* getMax(node* root)
{
if(root == nullptr)
return root;
return(root->right == nil)?root: getMax(root->right);
}
void remove(int &key, node* &root)
{
if(root == nil)
return;
else if(key < root->key)
remove(key,root->left);
else if(key > root->key)
remove(key,root->right);
else if(root->left != nil && root->right != nil)
{
root->key = getMax(root->left)->key;
remove(root->key,root->left);
}
else
delete_one_child(root);
}
bool is_leaf(node* n)
{
return (n->right == nullptr && n->left == nullptr);
}
void replace_node(node* a, node *b)
{
node* p = a->parent;
(p->left == a)? p->left = b : p->right = b;
b->parent = p;
}
void delete_one_child(node *n)
{
node *child = is_leaf(n->right) ? n->left : n->right;
replace_node(n, child);
if (n->color == BLACK)
{
if (child->color == RED)
child->color = BLACK;
else
delete_case1(child);
}
delete n;
}
void insert(int x)
{
insert(x,root,nullptr);
}
//functii extra
void show(node* x)
{
if(x!= nil)
{
cout<<x->key<<" ";
if (x->color == BLACK)
cout<<"BLACK";
else cout<< "RED";
cout<<" si are copii pe : "<<x->left->key <<" && "<<x->right->key<<" ;";
show(x->left);
show(x->right);
}
}
void delete_case1(node *n)
{
if (n->parent != nullptr)
delete_case2(n);
}
void delete_case2(node *n)
{
node *s = sibling(n);
if (s->color == RED)
{
n->parent->color = RED;
s->color = BLACK;
if (n == n->parent->left)
leftRotate(root,n->parent);
else
rightRotate(root,n->parent);
}
delete_case3(n);
}
void delete_case3(node *n)
{
node *s = sibling(n);
if ((n->parent->color == BLACK) &&
(s->color == BLACK) &&
(s->left->color == BLACK) &&
(s->right->color == BLACK))
{
s->color = RED;
delete_case1(n->parent);
}
else
delete_case4(n);
}
void delete_case4(node *n)
{
node *s = sibling(n);
if ((n->parent->color == RED) &&
(s->color == BLACK) &&
(s->left->color == BLACK) &&
(s->right->color == BLACK))
{
s->color = RED;
n->parent->color = BLACK;
}
else
delete_case5(n);
}
void delete_case5(node *n)
{
node *s = sibling(n);
if (s->color == BLACK)
{
/* this if statement is trivial,
due to case 2 (even though case 2 changed the sibling to a sibling's child,
the sibling's child can't be red, since no red parent can have a red child). */
/* the following statements just force the red to be on the left of the left of the parent,
or right of the right, so case six will rotate correctly. */
if ((n == n->parent->left) &&
(s->right->color == BLACK) &&
(s->left->color == RED))
{ /* this last test is trivial too due to cases 2-4. */
s->color = RED;
s->left->color = BLACK;
rightRotate(root,s);
}
else if ((n == n->parent->right) &&
(s->left->color == BLACK) &&
(s->right->color == RED))
{/* this last test is trivial too due to cases 2-4. */
s->color = RED;
s->right->color = BLACK;
leftRotate(root,s);
}
}
delete_case6(n);
}
void delete_case6(node *n)
{
node *s = sibling(n);
s->color = n->parent->color;
n->parent->color = BLACK;
if (n == n->parent->left)
{
s->right->color = BLACK;
leftRotate(root,n->parent);
}
else
{
s->left->color = BLACK;
rightRotate(root,n->parent);
}
}
bool search(int x)
{
return search(x,root);
}
void remove(int x)
{
if(search(x))
remove(x,root);
}
void srd(node*root)
{
if(root!= nil)
{
cout<<"{ "<<root->key<<" ";
if(root->color== 0)
cout<<"BLACK ";
else
cout<<"RED ";
cout<<" {"<<root->left->key<<" , "<<root->right->key<<" }\n";
srd(root->left);
//out<<root->key<<" ";
srd(root->right);
}
}
void showSorted()
{
srd(root);
}
};
//functia unde testam operatiile
//BST bst;
//AVL avl;
//Treap treap;
//set<int> um;
RBT rbt;
int main()
{
int n,x,op,nr,nr2,j=0;
hin >> n;
for(int i = 0 ; i< n ; i++)
{
hin >> op >> x;
//in >>x;
switch(op)
{
case 1:
rbt.insert(x);
//treap.insert(x);
//avl.insert(x);
//bst.insert(x);
// um.insert(x);
break;
case 2:
//cout<<"\ninainte ca "<<x<<" sa fie sters\n";
//rbt.showSorted();
rbt.remove(x);
//cout<<"\ndupa ce "<<x<<"a fost sters\n";
//rbt.showSorted();
//treap.erase(x);
//um.erase(x);
//bst.erase(x);
//avl.remove(x);
break;
case 3:
nr = rbt.search(x);
//nr = treap.find(x);
//nr = avl.find(x);
//nr = bst.find(x);
//nr2 = (um.find(x)!=um.end())?1:0;
hout<<nr<<'\n';
//ing>> nr2;
//j++;
//if(nr != nr2)
// cout<<"linia "<<j<<" "<<nr<<"!="<<nr2<<"elementul "<<x<<'\n';
break;
}
//rbt.insert(x);
//avl.insert(x);
//treap.insert(x);
//bst.insert(x);
}
//rbt.showSorted();
//avl.showSorted();
//treap.showSorted();
//bst.showSorted();z
}