Splay
#define lch ch[0]
#define rch ch[1]
class Splay{
private:
struct Node{
int val,cnt,sz;
Node *fa,*ch[2];
inline void pushup(){
sz=cnt;
if(lch) sz+=lch->sz;
if(rch) sz+=rch->sz;
}
inline bool checkson(){
return this==fa->rch;
}
Node(){}
Node(int x){
val=x;cnt=1;sz=1;
fa=lch=rch=nullptr;
}
Node(int x,Node *ptr){
val=x;cnt=1;sz=1;
fa=ptr;
lch=rch=nullptr;
}
};
Node *rt;
inline void rotate(Node *x){
assert(x);
Node *y=x->fa,*z=y->fa;
int dir=!x->checkson();
y->ch[!dir]=x->ch[dir];
if(x->ch[dir]) x->ch[dir]->fa=y;
x->ch[dir]=y;
y->fa=x;
x->fa=z;
if(z) z->ch[y==z->rch]=x;
y->pushup();
x->pushup();
}
inline void splay(Node *cur){
assert(cur);
if(cur==rt) return;
Node *curfa;
while(cur->fa){
curfa=cur->fa;
if(curfa->fa) rotate(cur->checkson()==curfa->checkson()?curfa:cur);
rotate(cur);
}
rt=cur;
}
inline Node* getrtpre(){
Node *cur=rt->lch;
if(!cur) return cur;
while(cur->rch) cur=cur->rch;
splay(cur);
return cur;
}
inline Node* getrtnxt(){
Node *cur=rt->rch;
if(!cur) return cur;
while(cur->lch) cur=cur->lch;
splay(cur);
return cur;
}
public:
inline void insert(int val){
if(!rt){
rt=new Node(val);
return;
}
Node *cur=rt,*curfa=nullptr;
while(true){
assert(cur);
if(cur->val==val){
cur->cnt++;
cur->pushup();
if(curfa) curfa->pushup();
splay(cur);
break;
}
curfa=cur;
cur=cur->ch[cur->val<val];
if(!cur){
curfa->ch[curfa->val<val]=new Node(val,curfa);
curfa->pushup();
splay(curfa->ch[curfa->val<val]);
break;
}
}
}
inline int query_val_rk(int val){
int res=0;
Node *cur=rt;
while(true){
assert(cur);
if(val < cur->val){
if(cur->lch) cur=cur->lch;
else return res+1;
}
else{
res+=cur->lch?cur->lch->sz:0;
if(val==cur->val){
splay(cur);
return res+1;
}
else{
res+=cur->cnt;
if(cur->rch) cur=cur->rch;
else return res+1;
}
}
}
}
inline int query_kth_val(int k){
Node *cur=rt;
while(true){
assert(cur);
if(cur->lch && k<=cur->lch->sz) cur=cur->lch;
else{
k-=cur->lch?cur->lch->sz:0;
if(k<=cur->cnt){
splay(cur);
return cur->val;
}
else{
k-=cur->cnt;
cur=cur->rch;
}
}
}
}
inline void del(int val){
query_val_rk(val);//splay [val] to root
if(rt->cnt>1){
rt->cnt--;
rt->pushup();
return;
}
//now [val] is the root, we need to del the root and merge its left and right sons
if((!rt->lch) && (!rt->rch)){
delete rt;
rt=nullptr;
}
else if(!rt->lch){
Node *tmp=rt;
rt=rt->rch;
rt->fa=nullptr;
delete tmp;
}
else if(!rt->rch){
Node *tmp=rt;
rt=rt->lch;
rt->fa=nullptr;
delete tmp;
}
else{
Node *oldrt=rt,*ptr=getrtpre();
oldrt->rch->fa=ptr;
ptr->rch=oldrt->rch;
delete oldrt;
rt->pushup();
}
}
inline int query_pre(int val){
Node *ptr;
int res;
insert(val);
ptr=getrtpre();
res=ptr?ptr->val:-0x3f3f3f3f;
del(val);
return res;
}
inline int query_nxt(int val){
Node *ptr;
int res;
insert(val);
ptr=getrtnxt();
res=ptr?ptr->val:-0x3f3f3f3f;
del(val);
return res;
}
};
Treap
#define lch ch[0]
#define rch ch[1]
mt19937 mt_rand(time(NULL));
class Treap{
private:
struct Node{
Node *ch[2];
int val,pri,cnt,sz;
Node(int v):val(v),cnt(1),sz(1){
lch=rch=nullptr;
pri=mt_rand();
}
void pushup(){
sz=cnt;
if(lch) sz+=ch[0]->sz;
if(rch) sz+=ch[1]->sz;
}
};
int qpre,qsuf;
inline void rotate(Node *&cur,int dir){
assert(cur);
Node *tmp=cur->ch[!dir];
cur->ch[!dir]=tmp->ch[dir];
tmp->ch[dir]=cur;
cur->pushup();
tmp->pushup();
cur=tmp;
}
public:
Node *root=nullptr;
void print(Node *x) {
if (!x) return;
cout<<x->val<<':'<<'[';
print(x->lch);
cout<<'|';
print(x->rch);
cout<<']';
}
void insert(Node *&cur,int val){
if(cur==nullptr){
cur=new Node(val);
return;
}
else if(val==cur->val){
cur->cnt++;
cur->sz++;
}
else if(val<cur->val){
insert(cur->lch,val);
if(cur->lch->pri < cur->pri) rotate(cur,1);
cur->pushup();
}
else{
insert(cur->rch,val);
if(cur->rch->pri < cur->pri) rotate(cur,0);
cur->pushup();
}
}
void del(Node *&cur,int val){
assert(cur);
if(val>cur->val){
del(cur->rch,val);
cur->pushup();
}
else if(val<cur->val){
del(cur->lch,val);
cur->pushup();
}
else{
if(cur->cnt>1){
cur->cnt--;
cur->sz--;
}
else{
int state=(int)(cur->lch!=nullptr)+(int)(cur->rch!=nullptr)*2;
Node *tmp=cur;
switch(state){
case 0:{
delete cur;
cur=nullptr;
break;
}
case 1:{
cur=tmp->lch;
delete tmp;
break;
}
case 2:{
cur=tmp->rch;
delete tmp;
break;
}
case 3:{
if(cur->lch->pri < cur->rch->pri){
rotate(cur,1);
del(cur->rch,val);
}
else{
rotate(cur,0);
del(cur->lch,val);
}
cur->pushup();
break;
}
}
}
}
}
int query_rank(Node *cur,int val){
assert(cur);
int lftsz=cur->lch==nullptr ? 0 : cur->lch->sz;
if(val==cur->val) return lftsz+1;
else if(val<cur->val) return query_rank(cur->lch,val);
else return lftsz+cur->cnt+query_rank(cur->rch,val);
}
int query_val(Node *cur,int rk){
assert(cur);
int lftsz=cur->lch==nullptr ? 0 : cur->lch->sz;
if(rk<=lftsz) return query_val(cur->lch,rk);
else if(rk<=lftsz+cur->cnt) return cur->val;
else return query_val(cur->rch,rk-lftsz-cur->cnt);
}
int query_pre(Node *cur,int val){
assert(cur);
if(val<=cur->val){
if(cur->lch) return query_pre(cur->lch,val);
}
else{
qpre=cur->val;
if(cur->rch) query_pre(cur->rch,val);
return qpre;
}
return -0x3f3f3f3f;
}
int query_suf(Node *cur,int val){
assert(cur);
if(val>=cur->val){
if(cur->rch) return query_suf(cur->rch,val);
}
else{
qsuf=cur->val;
if(cur->lch) query_suf(cur->lch,val);
return qsuf;
}
return -0x3f3f3f3f;
}
};
Fhq-Treap
#define lch t[pos].ls
#define rch t[pos].rs
mt19937 mt_rand(time(NULL));
class FhqTreap{
private:
int cnt;
inline int newnode(int v){
t[++cnt].sz=1;
t[cnt].val=v;
t[cnt].pri=mt_rand();
t[cnt].ls=t[cnt].rs=0;
return cnt;
}
inline void pushup(int pos){
t[pos].sz=t[lch].sz+t[rch].sz+1;//tag
}
void split(int pos,int x,int &L,int &R){
if(pos==0){
L=R=0;
return;
}
if(x>=t[pos].val){
L=pos;
split(rch,x,rch,R);
}
else{
R=pos;
split(lch,x,L,lch);
}
pushup(pos);
}
int merge(int L,int R){
if(L==0||R==0) return L+R;
if(t[L].pri<t[R].pri){
t[L].rs=merge(t[L].rs,R);
pushup(L);
return L;
}
else{
t[R].ls=merge(L,t[R].ls);
pushup(R);
return R;
}
}
public:
struct Node{
int ls,rs,val,pri,sz;
}t[MAXN];
int root;
inline void insert(int x){//tag
int L,R;
split(root,x,L,R);
root=merge(merge(L,newnode(x)),R);
}
inline void del(int x){
int L,R,P;
split(root,x,L,R);
split(L,x-1,L,P);
root=merge(merge(L,merge(t[P].ls,t[P].rs)),R);
}
inline int query_rank(int x){
int L,R,res;
split(root,x-1,L,R);
res=t[L].sz+1;
merge(L,R);
return res;
}
int query_kth(int pos,int k){
if(k==t[lch].sz+1) return pos;
else if(k<t[lch].sz+1) return query_kth(lch,k);
else return query_kth(rch,k-t[lch].sz-1);//tag
}
inline int query_pre(int x){
int L,R,res;
split(root,x-1,L,R);
res=t[query_kth(L,t[L].sz)].val;
merge(L,R);
return res;
}
inline int query_suf(int x){
int L,R,res;
split(root,x,L,R);
res=t[query_kth(R,1)].val;
merge(L,R);
return res;
}
};