数据结构:Treap

时间:2023-03-09 07:20:40
数据结构:Treap

关于重量平衡树的相关概念可以参考姊妹文章:重量平衡树之替罪羊树

Treap是依靠旋转来维护平衡的重量平衡树中最为好写的一中,因为它的旋转不是LL就是RR

对于每一个新的节点,它给这个节点分配了一个随机数,用作优先级,然后以这个优先级来维护一个堆结构

由于堆本身就是完全二叉树结构,这样维护之后的树就无限接近于完全二叉树,所以还是很神奇的

这棵树满足BST的一切性质,除了不能处理序列问题之外已经无敌了

应该说,抛去动态树问题之外,这是实战最好用的树了

我们还是先看定义:

struct Tree
{
int v,w;
int size;
int rnd;
int ch[];
}t[maxn];
int root;
int size;
int ans=;

在这里v是值,w是同值的节点个数,size是子树的节点总数,rnd是优先级,外面:root是根节点,size是根节点中元素个数,ans是统计答案用的临时变量

我们这里还是先介绍插入操作,平衡树问题如果不是处理序列的,建议就一个一个插

void insert(int &k,int x)
{
if(k==)
{
size++;
k=size;
t[k].size=t[k].w=;
t[k].v=x;
t[k].rnd=rand();
return;
}
t[k].size++;
if(t[k].v==x)
t[k].w++;
else if(x>t[k].v)
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
lturn(k);
}
else
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
rturn(k);
}
}

插入时根据是否是叶子节点,遍历到的节点的w值等进行维护

每次插入要判断一下是否满足堆结构,进行相应的旋转调整

下面给出旋转调整的函数,基本上可以作为左旋和右旋的模板了

void rturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}
void lturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}

然后我们给出update函数,这里要维护的东西很少,只有一个size,所以这个时候的update就是更新size用的

void update(int k)
{
t[k].size=t[t[k].ch[]].size+t[t[k].ch[]].size+t[k].w;
}

然后是四种基本查询工作,各种平衡树基本一致,也可以作为模板记下来了

int query_rank(int k,int x)
{
if(k==)
return ;
if(t[k].v==x)
return t[t[k].ch[]].size+;
else if(x>t[k].v)
return t[t[k].ch[]].size+t[k].w+query_rank(t[k].ch[],x);
else
return query_rank(t[k].ch[],x);
}
int query_num(int k,int x)
{
if(k==)
return ;
if(x<=t[t[k].ch[]].size)
return query_num(t[k].ch[],x);
else if(x>t[t[k].ch[]].size+t[k].w)
return query_num(t[k].ch[],x-t[t[k].ch[]].size-t[k].w);
else
return t[k].v;
}
void query_pro(int k,int x)
{
if(k==)
return;
if(t[k].v<x)
ans=k,query_pro(t[k].ch[],x);
else
query_pro(t[k].ch[],x);
}
void query_sub(int k,int x)
{
if(k==)
return;
if(t[k].v>x)
ans=k,query_sub(t[k].ch[],x);
else
query_sub(t[k].ch[],x);
}

最后我们给出完整的模板,这棵树一定要熟练掌握,只要是平衡树问题,很大可能都是用它来完成的

 #include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=;
int n;
struct Tree
{
int v,w;
int size;
int rnd;
int ch[];
}t[maxn];
int root;
int size;
int ans=;
void update(int k)
{
t[k].size=t[t[k].ch[]].size+t[t[k].ch[]].size+t[k].w;
}
void rturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}
void lturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}
void insert(int &k,int x)
{
if(k==)
{
size++;
k=size;
t[k].size=t[k].w=;
t[k].v=x;
t[k].rnd=rand();
return;
}
t[k].size++;
if(t[k].v==x)
t[k].w++;
else if(x>t[k].v)
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
lturn(k);
}
else
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
rturn(k);
}
}
void del(int &k,int x)
{
if(k==)
return;
if(t[k].v==x)
{
if(t[k].w>)
{
t[k].w--;
t[k].size--;
return;
}
if(t[k].ch[]*t[k].ch[]==)
k=t[k].ch[]+t[k].ch[];
else if(t[t[k].ch[]].rnd<t[t[k].ch[]].rnd)
rturn(k),del(k,x);
else
lturn(k),del(k,x);
}
else if(x>t[k].v)
t[k].size--,del(t[k].ch[],x);
else
t[k].size--,del(t[k].ch[],x);
}
int query_rank(int k,int x)
{
if(k==)
return ;
if(t[k].v==x)
return t[t[k].ch[]].size+;
else if(x>t[k].v)
return t[t[k].ch[]].size+t[k].w+query_rank(t[k].ch[],x);
else
return query_rank(t[k].ch[],x);
}
int query_num(int k,int x)
{
if(k==)
return ;
if(x<=t[t[k].ch[]].size)
return query_num(t[k].ch[],x);
else if(x>t[t[k].ch[]].size+t[k].w)
return query_num(t[k].ch[],x-t[t[k].ch[]].size-t[k].w);
else
return t[k].v;
}
void query_pro(int k,int x)
{
if(k==)
return;
if(t[k].v<x)
ans=k,query_pro(t[k].ch[],x);
else
query_pro(t[k].ch[],x);
}
void query_sub(int k,int x)
{
if(k==)
return;
if(t[k].v>x)
ans=k,query_sub(t[k].ch[],x);
else
query_sub(t[k].ch[],x);
}
int main()
{
cin>>n;
int tmp,x;
for(int i=;i<=n;i++)
{
cin>>tmp>>x;
switch(tmp)
{
case :insert(root,x);break;
case :del(root,x);break;
case :cout<<query_rank(root,x)<<endl;break;
case :cout<<query_num(root,x)<<endl;break;
case :ans=;query_pro(root,x);cout<<t[ans].v<<endl;break;
case :ans=;query_sub(root,x);cout<<t[ans].v<<endl;break;
}
}
return ;
}