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