# 大家都很强， 可与之共勉。

Treap = Tree + Heap.

Treap 维护堆的性质的方法只用到了左旋和右旋， 编程复杂度比Splay小一点， 并且在两者可完成的操作速度有明显优势

## 开始

typedef class TreapNode  {
public:
int val;
int siz, key, same;
TreapNode *ls, *rs;

inline TreapNode ( )  {     }
inline TreapNode ( int val, TreapNode* & node ) : val ( val ), key ( rand ( ) ), siz ( 1 ), same ( 1 ) {    ls = rs = node; }

inline void update ( )  {
siz = ls -> siz + rs -> siz + same;
}
} Node;

## 关于随机函数

< cstdlib > 中的rand ( ) 速度比较慢， 而在数据结构中对于素的如果要求过高， 可以使用手写 rand ( )。

inline int rand ( )  {
static int seed = 233;
return seed = ( int ) seed * 482711LL % 2147483647;
}

## 首先是旋转操作

inline void Zig ( Node* &nd )  {
tmp = nd -> ls;
if ( tmp == null ) return;
nd -> ls = tmp -> rs;
tmp -> rs = nd;
tmp -> siz = nd -> siz;
nd -> update ( );
nd = tmp;
}

inline void Zag ( Node* &nd )  {
tmp = nd -> rs;
if ( tmp == null ) return;
nd -> rs = tmp -> ls;
tmp -> ls = nd;
tmp -> siz = nd -> siz;
nd -> update ( );
nd = tmp;
}

## 接下来是插入操作

inline void Insert ( Node* &nd, int& val )  {
if ( nd == null )  {
nd = ++tail;
*nd = Node ( val, null );
return;
}

if ( nd -> val == val )  ++nd -> same;
else  {
if ( val > nd -> val )  {
Insert ( nd -> rs, val );
if ( nd -> rs -> key < nd -> key )
Zag ( nd );
}   else  {
Insert ( nd -> ls, val );
if ( nd -> ls -> key < nd -> key )
Zig ( nd );
}
}

nd -> update ( );
}

## 之后是删除操作

### 注意：

#### 不要忘了update()!!!

inline void Delete ( Node* &nd, int x )  {
if ( nd == null )  return;
if ( nd -> val == x )  {
if ( nd -> same > 1 )  {
--nd -> same; nd -> update ( ); return;
}
if ( nd -> ls == null && nd -> rs == null ) { nd = null; return;  }
else if ( nd -> ls == null && nd -> rs )  nd = nd -> rs;
else if ( nd -> ls && nd -> rs == null )  nd = nd -> ls;
if ( nd -> ls -> key < nd -> rs -> key ) { Zig ( nd ); Delete ( nd -> rs, x );  }
else  { Zag ( nd ); Delete ( nd -> ls, x );  }
}  else if ( x > nd -> val )  Delete ( nd -> rs, x );
else  Delete ( nd -> ls, x );
nd -> update ( );
}


inline int query_pre ( Treap* &nd, int val )  {
if ( nd == null )  return 0xefefefef;
if ( val < nd -> val )
return query_pre ( nd -> ls, val );
return max ( nd -> val, query_pre ( nd -> rs, val ) );
}

inline int query_post ( Treap* &nd, int val )  {
if ( nd == null )  return 0x7fffffff;
if ( val > nd -> val )
return query_post ( nd -> rs, val );
return min ( nd -> val, query_post ( nd -> ls, val ) );
}

inline void query_pre ( Node* &nd, int &ans, int val )  {
if ( nd == null )  return;
if ( val > nd -> val )
ans = nd -> val, query_pre ( nd -> rs, ans, val );
else query_pre ( nd -> ls, ans, val );
}

inline void query_post ( Node* &nd, int &ans, int val )  {
if ( nd == null )  return;
if ( val < nd -> val )
ans = nd -> val, query_post ( nd -> ls, ans, val );
else query_post ( nd -> rs, ans, val );
}

#include <bits/stdc++.h>

unsigned int seed, n, opt;

int ans, x;

inline int rand ( )  {
return seed = ( int ) seed * 482711LL % 2147483647;
}

typedef class TreapNode  {
public:
int val;
int siz, key, same;
TreapNode *ls, *rs;

inline TreapNode ( )  {     }
inline TreapNode ( int val, TreapNode* & node ) : val ( val ), key ( rand ( ) ), siz ( 1 ), same ( 1 ) {    ls = rs = node; }

inline void update ( )  {
siz = ls -> siz + rs -> siz + same;
}
} Node;

Node *pool, *root, *tail, *null, *tmp;

inline void Init ( )  {
seed = 233;
pool = new Node [ n + 5 ];
root = null = tail = pool;
null -> siz = 0, null -> same = 0, null -> val = 0, null -> key = rand( ), null -> ls = null -> rs = null;
}

inline void Zig ( Node* &nd )  {
tmp = nd -> ls;
if ( tmp == null ) return;
nd -> ls = tmp -> rs;
tmp -> rs = nd;
tmp -> siz = nd -> siz;
nd -> update ( );
nd = tmp;
}

inline void Zag ( Node* &nd )  {
tmp = nd -> rs;
if ( tmp == null ) return;
nd -> rs = tmp -> ls;
tmp -> ls = nd;
tmp -> siz = nd -> siz;
nd -> update ( );
nd = tmp;
}

inline void Insert ( Node* &nd, int& val )  {
if ( nd == null )  {
nd = ++tail;
*nd = Node ( val, null );
return;
}

if ( nd -> val == val )  ++nd -> same;
else  {
if ( val > nd -> val )  {
Insert ( nd -> rs, val );
if ( nd -> rs -> key < nd -> key )
Zag ( nd );
}   else  {
Insert ( nd -> ls, val );
if ( nd -> ls -> key < nd -> key )
Zig ( nd );
}
}

nd -> update ( );
}

inline int kth ( Node* &nd, int k )  {
int tmp = nd -> ls -> siz + nd -> same;
if ( nd -> ls -> siz < k && k <= tmp )  return nd -> val;
return nd -> ls -> siz >= k ? kth ( nd -> ls, k ) : kth ( nd -> rs, k - tmp );
}

inline void Delete ( Node* &nd, int x )  {
if ( nd == null )  return;
if ( nd -> val == x )  {
if ( nd -> same > 1 )  {
--nd -> same; nd -> update ( ); return;
}
if ( nd -> ls == null && nd -> rs == null ) { nd = null; return;  }
else if ( nd -> ls == null && nd -> rs )  nd = nd -> rs;
else if ( nd -> ls && nd -> rs == null )  nd = nd -> ls;
if ( nd -> ls -> key < nd -> rs -> key ) { Zig ( nd ); Delete ( nd -> rs, x );  }
else  { Zag ( nd ); Delete ( nd -> ls, x );  }
}  else if ( x > nd -> val )  Delete ( nd -> rs, x );
else  Delete ( nd -> ls, x );
nd -> update ( );
}

inline int query_rank ( Node* &nd, int x )  {
if ( nd == null )  return 0;
if ( nd -> val == x )  return nd -> ls -> siz + 1;
else  return  ( x > nd -> val ) ? nd -> ls -> siz + nd -> same + query_rank ( nd -> rs, x )
: query_rank ( nd -> ls, x );
}

inline void query_pre ( Node* &nd, int &ans, int val )  {
if ( nd == null )  return;
if ( val > nd -> val )
ans = nd -> val, query_pre ( nd -> rs, ans, val );
else query_pre ( nd -> ls, ans, val );
}

inline void query_post ( Node* &nd, int &ans, int val )  {
if ( nd == null )  return;
if ( val < nd -> val )
ans = nd -> val, query_post ( nd -> ls, ans, val );
else query_post ( nd -> rs, ans, val );
}

using std :: cin;
using std :: cout;
using std :: endl;

int main ( )  {
cin >> n;
Init ( );
register int i = 1;
loop :;  {
cin >> opt >> x;
switch ( opt )  {
case 1:
Insert ( root, x );  break;
case 2:
Delete ( root, x );  break;
case 3:
cout << query_rank( root, x ) << endl; break;
case 4:
cout << kth ( root, x ) << endl; break;
case 5:
query_pre ( root, ans, x ); cout << ans << endl; break;
case 6:
query_post ( root, ans, x ); cout << ans << endl; break;
}
}  if ( ++i <= n )  goto loop;
}