旋转Treap
treap是一种弱平衡的二叉搜索树,同时符合二叉搜索树和堆的性质,堆一般用随机值的小根堆。
旋转treap在每次有修改操作时,通过比较节点的优先值来决定是否旋转,通过旋转来维持树的平衡。
不维护自身副本数,左子树小于等于根节点,右子树严格大于根节点。
struct Treap{
struct tree{
int ch[2],v,p,w;
}t[N];
int root,tot;
unsigned long long inf=1e10;
#define l(p) (t[p].ch[0])
#define r(p) (t[p].ch[1])
#define ch(p,x) (t[p].ch[x])
#define v(p) (t[p].v)
#define w(p) (t[p].w)
#define p(x) (t[x].p)
inline int rand(){
static default_random_engine x;
static uniform_int_distribution<int>f(-1e8,1e8);
return f(x);
}
inline int create(int x){
t[++tot]={0,0,x,rand(),1};
return tot;
}
inline void pushup(int p){
w(p)=w(l(p))+w(r(p))+1;/*size包括自己*/
}
inline void rotate(int&p,int d){//d=0左旋,相当于与右孩子交换,d=1右旋,相当于与左孩子交换
int x=ch(p,d^1);/*记录要变成根的子树*/
ch(p,d^1)=ch(x,d);/*每一个值在记录后都立刻改变*/
ch(x,d)=p;/*原根变为其子树*/
pushup(p);
p=x;
}
void insert(int&p,int x){
if(!p){
p=create(x);
return;
}
int d=v(p)<x;/*x<=v(p)时递归左子树*/
insert(ch(p,d),x);
if(p(p)>p(ch(p,d)))rotate(p,d^1);/*若递归方向的子树优先级小于根节点将该节点旋转上来*/
pushup(p);
}
void del(int&p,int x){
if(!p)return;/*不存在节点则return*/
if(v(p)==x){/*找到对应点*/
if(!l(p)||!r(p)){/*只有一个节点直接删除即可*/
p=l(p)|r(p);
return;/*直接return,不再pushup*/
}
else{
int d=p(l(p))<p(r(p));/*将优先级小的子节点旋转上来,根节点一直旋转到叶子节点进行删除*/
rotate(p,d);/*与左孩子交换相当于右旋,与右孩子交换相当于左旋*/
del(ch(p,d),x);/*递归转下去的根进行删除*/
}
}
else del(ch(p,v(p)<x),x);/*x<=v(p)的情况递归左子树,否则递归右子树*/
pushup(p);
}
/*
递归写法
int rank(int p,int x){
if(!p)return 1;
if(x<=v(p))return rank(l(p),x);
else return rank(r(p),x)+w(l(p))+1;
}
int kth(int p,int x){
if(!p)return inf;
if(w(l(p))+1==x)return v(p);
else if(x<=w(l(p)))return kth(l(p),x);
else return kth(r(p),x-w(l(p))-1);
}
*/
inline int rank(int x){
int p=root,re=1;/*初始化排名为1*/
while(p){
if(x<=v(p))p=l(p);/*查询最小排名,查到x时要递归左子树*/
else re+=w(l(p))+1,p=r(p);/*加上左子树的大小*/
}
return re;
}
inline int kth(int x){
int p=root;
while(w(l(p))+1!=x){/*尚未找到相应排名*/
if(x<=w(l(p)))p=l(p);/*对应的数在左子树*/
else x-=w(l(p))+1,p=r(p);/*对应的数在右子树,更新排名*/
}
return v(p);
}
int pre(int p,int x){
if(!p)return -inf;/*在所有小于x的点中取max*/
if(v(p)<x)return max(v(p),pre(r(p),x));/*当前点已经小于x,在右子树中找介于当前点和x之间的数*/
else return pre(l(p),x);/*当前点已经大于x,在左子树中介于当前点和x之间的数*/
}
int suc(int p,int x){
if(!p)return inf;/*在所有大于x的点中取min*/
if(v(p)>x)return min(v(p),suc(l(p),x));/*当前点已经大于x,在左子树中找介于当前点和x之间的数*/
else return suc(r(p),x);/*当前点已经小于x,在右子树中找介于当前点和x之间的数*/
}
inline int rank(int x){
return rank(root,x);
}
inline void insert(int x){
insert(root,x);
}
inline void del(int x){
del(root,x);
}
inline int pre(int x){
return pre(root,x);
}
inline int suc(int x){
return suc(root,x);
}
};
每个节点维护一个副本数,左子树严格小于根节点,右子树严格大于根节点。
struct Treap{
struct tree{
int ch[2],v,p,w,c/*节点副本数*/;
}t[N];
int root,tot;
unsigned long long inf=1e10;
#define l(p) (t[p].ch[0])
#define r(p) (t[p].ch[1])
#define ch(p,x) (t[p].ch[x])
#define v(p) (t[p].v)
#define w(p) (t[p].w)
#define p(x) (t[x].p)
#define c(p) (t[p].c)
inline int rand(){
static default_random_engine x;
static uniform_int_distribution<int>f(-1e8,1e8);
return f(x);
}
inline int create(int x){
t[++tot]={0,0,x,rand(),1,1};
return tot;
}
inline void pushup(int p){
w(p)=w(l(p))+w(r(p))+c(p);/*size包括自己的所有副本*/
}
inline void rotate(int&p,int d){//d=0左旋,相当于与右孩子交换,d=1右旋,相当于与左孩子交换
int x=ch(p,d^1);/*记录要变成根的子树*/
ch(p,d^1)=ch(x,d);/*每一个值在记录后都立刻改变*/
ch(x,d)=p;/*原根变为其子树*/
pushup(p);
p=x;
}
void insert(int&p,int x){
if(!p){
p=create(x);
return;
}
if(v(p)==x){
c(p)++;
pushup(p);
return;
}
int d=v(p)<x;/*x<v(p)时递归左子树*/
insert(ch(p,d),x);
if(p(p)>p(ch(p,d)))rotate(p,d^1);/*若递归方向的子树优先级小于根节点将该节点旋转上来*/
pushup(p);
}
inline void del(int&p,int x){
if(!p)return;/*不存在节点则return*/
if(v(p)==x){/*找到对应点*/
if(c(p)>1){/*副本数大于1可以直接减少副本*/
c(p)--;
pushup(p);
return;
}
if(!l(p)||!r(p)){/*只有一个节点直接删除即可*/
p=l(p)|r(p);
return;/*直接return,不再pushup*/
}
else{
int d=p(l(p))<p(r(p));/*将优先级小的子节点旋转上来,根节点一直旋转到叶子节点进行删除*/
rotate(p,d);/*与左孩子交换相当于右旋,与右孩子交换相当于左旋*/
del(ch(p,d),x);/*递归转下去的根进行删除*/
}
}
else del(ch(p,v(p)<x),x);/*x<=v(p)的情况递归左子树,否则递归右子树*/
pushup(p);
}
/*
递归写法
int rank(int p,int x){
if(!p)return 1;
if(x<=v(p))return rank(l(p),x);
else return rank(r(p),x)+w(l(p))+1;
}
int kth(int p,int x){
if(!p)return inf;
if(w(l(p))+1==x)return v(p);
else if(x<=w(l(p)))return kth(l(p),x);
else return kth(r(p),x-w(l(p))-1);
}
*/
inline int rank(int x){
int p=root,re=1;/*初始化排名为1*/
while(p){
if(x<=v(p))p=l(p);/*查询最小排名,查到x时要递归左子树*/
else re+=w(l(p))+1,p=r(p);/*加上左子树的大小*/
}
return re;
}
inline int kth(int x){
int p=root;
while(w(l(p))+1!=x){/*尚未找到相应排名*/
if(x<=w(l(p)))p=l(p);/*对应的数在左子树*/
else x-=w(l(p))+1,p=r(p);/*对应的数在右子树,更新排名*/
}
return v(p);
}
int pre(int p,int x){
if(!p)return -inf;/*在所有小于x的点中取max*/
if(v(p)<x)return max(v(p),pre(r(p),x));/*当前点已经小于x,在右子树中找介于当前点和x之间的数*/
else return pre(l(p),x);/*当前点已经大于x,在左子树中介于当前点和x之间的数*/
}
int suc(int p,int x){
if(!p)return inf;/*在所有大于x的点中取min*/
if(v(p)>x)return min(v(p),suc(l(p),x));/*当前点已经大于x,在左子树中找介于当前点和x之间的数*/
else return suc(r(p),x);/*当前点已经小于x,在右子树中找介于当前点和x之间的数*/
}
inline int rank(int x){
return rank(root,x);
}
inline void insert(int x){
insert(root,x);
}
inline void del(int x){
del(root,x);
}
inline int pre(int x){
return pre(root,x);
}
inline int suc(int x){
return suc(root,x);
}
}t;