学习:treap
背景
由于对于普通的二叉搜索树,
随机数据倒是没有什么
但是构造数据很容易就会其退化为1条链
也就是说从\(O(log_n)\)的优秀复杂度退化到\(O(n)\)
有人想到,可以对深度太深的树进行一次中序遍历
重新来构建这颗树,也就是替罪羊树,
但是实在是太暴力,而且不太好写
所以人们想到了另一个方案,treap
原理
treap从字母的构成上很像tree+heap,也就是树+堆
我们对每一个节点设定一个优先值,
同时,对于这个节点的两个儿子
一定会满足左儿子的优先级<当前节点的优先级>右儿子的优先级
也就是我们强行将构造的数据转换成随机的数据,
所以期望的时间复杂度\(O(log_n)\)
操作&代码
旋转
void update(int k)
{
tre[k].siz=tre[tre[k].chil[0]].siz+tre[tre[k].chil[1]].siz+tre[k].cnt;
}
void rotate(int &x,int d)
{
int son=tre[x].chil[d];
tre[x].chil[d]=tre[son].chil[d^1];
tre[son].chil[d^1]=x;
update(x);
x=son;
update(x);
}
插入
void insert(int &x,int val)
{
if(!x)
{
x=++cnt;
tre[x].cnt=tre[x].siz=1;
tre[x].val=val;
tre[x].rd=rand();
return;
}
else
{
tre[x].siz++;
if(tre[x].val==val)
{
tre[x].cnt++;
return;
}
int d=tre[x].val<val;
insert(tre[x].chil[d],val);
if(tre[x].rd>tre[tre[x].chil[d]].rd)
rotate(x,d);
}
}
cnt与这个数重合的数的个数
删除
void delet(int &x,int val)
{
if(!x)
return;
if(tre[x].val==val)
{
if(tre[x].cnt>1)
{
tre[x].cnt--;
tre[x].siz--;
return;
}
int d=tre[tre[x].chil[0]].rd>tre[tre[x].chil[1]].rd;
if(tre[x].chil[0]==0||tre[x].chil[1]==0)
x=tre[x].chil[0]+tre[x].chil[1];
else
{
rotate(x,d);
delet(x,val);
}
}
else
{
tre[x].siz--;
int d=tre[x].val<val;
delet(tre[x].chil[d],val);
}
}
查找是队列中的第几小(排名)
int find_rank(int x,int val)
{
if(!x)
return 0;
if(tre[x].val==val)
return tre[tre[x].chil[0]].siz+1;
if(tre[x].val>val)
return find_rank(tre[x].chil[0],val);
return find_rank(tre[x].chil[1],val)+tre[tre[x].chil[0]].siz+tre[x].cnt;
}
第几小
int find_kth(int root,int k)
{
int x=root;
while(1)
{
if(k<=tre[tre[x].chil[0]].siz)
x=tre[x].chil[0];
else if(k>tre[tre[x].chil[0]].siz+tre[x].cnt)
{
k=k-tre[tre[x].chil[0]].siz-tre[x].cnt;
x=tre[x].chil[1];
}
else
return tre[x].val;
}
}
前驱&后继
int pre(int x,int val)
{
if(!x)
return INT_MIN;
if(tre[x].val>=val)
return pre(tre[x].chil[0],val);
return max(pre(tre[x].chil[1],val),tre[x].val);
}
int suf(int x,int val)
{
if(!x)
return INT_MAX;
if(tre[x].val<=val)
return suf(tre[x].chil[1],val);
return min(suf(tre[x].chil[0],val),tre[x].val);
}

浙公网安备 33010602011771号