【Treap】
【介绍】
树堆,在数据结构中也称Treap(tree+heap),是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。其基本操作的期望时间复杂度为O(logn)。相对于其他的平衡二叉搜索树,Treap的特点是实现简单,且能基本实现随机平衡的结构。
【操作】
注:
struct Treap
{
Treap* son[2];
int x,w,s,ran; //x表示这个节点的权值,son[0]表示这个节点的左儿子,son[1]表示这个节点的右儿子,w表示该权值的数的个数,s表示这个节点的子树的的节点的w的总和,ran表示随机的权值。
int Cmp(int k) {if (k<x) return 0; if (k>x) return 1; return -1;}
void Pushup() {s=son[0]->s+son[1]->s+w;};
}a[maxn];
Treap* New(int x,int p)
{
++tot; a[tot].w=a[tot].s=p; a[tot].x=x; a[tot].ran=rand();
a[tot].son[0]=a[tot].son[1]=Null;
return &a[tot];
}
本人维护的是小根堆。(也可以维护大根堆)
① 旋转:
void Turn(Treap* &k,int d)
{
Treap* t=k->son[d]; k->son[d]=t->son[d^1]; t->son[d^1]=k;
t->s=k->s; k->Pushup(); k=t;
}
② 插入x数:
void Insert(Treap* &k,int x,int p)
{
if (k==Null) {k=New(x,p); return;}
int d=k->Cmp(x); k->s+=p;
if (d<0) k->w+=p;
else
{
Insert(k->son[d],x,p);
if (k->son[d]->ran<k->ran) Turn(k,d);
}
}
③ 删除x数:
void Delete(Treap* &k,int x)
{
if (k==Null) return;
int d=k->Cmp(x);
if (d<0)
{
if (k->w>1) {k->w--; k->s--; return;}
else if (k->son[0]==Null) k=k->son[1];
else if (k->son[1]==Null) k=k->son[0];
else if (k->son[0]->ran<k->son[1]->ran) {Turn(k,0); Delete(k,x);} else {Turn(k,1); Delete(k,x);}
}
else k->s--,Delete(k->son[d],x);
}
④ 查询x数的排名:
int Rank(Treap* k,int x)
{
if (k==Null) return -1;
int d=k->Cmp(x);
if (d<0) return k->son[0]->s+1;
else if (!d) return Rank(k->son[0],x);
else return k->son[0]->s+k->w+Rank(k->son[1],x);
}
⑤ 查询排名为x的数:
int Num(Treap* k,int x)
{
if (k==Null) return 0;
if (x<=k->son[0]->s) return Num(k->son[0],x);
else if (x>k->son[0]->s+k->w) return Num(k->son[1],x-k->son[0]->s-k->w);
else return k->x;
}
⑥ 查询x数有几个:
int Number(Treap* k,int x)
{
if (k==Null) return -1;
int d=k->Cmp(x);
if (d<0) return k->w; return Number(k->son[d],x);
}
⑦ 求x的前驱:
int Pre(Treap* k,int x)
{
if (k==Null) return -1;
if (x>k->x) {ans=k->x; Pre(k->son[1],x);} else Pre(k->son[0],x);
}
⑧ 求x的后继:
int Sub(Treap* k,int x)
{
if (k==Null) return -1;
if (x<k->x) {ans=k->x; Sub(k->son[0],x);} else Sub(k->son[1],x);
}
【例题】
bzoj3224