版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/82774698
前言
年轻时候写过一篇Treap原理,新写一篇的原因是想将它改造成类的形式并且添加lower_bound,upper_bound等实用函数。
BGM: Senbonzakura [SS-Extended+Bass]
接口
template <typename T>
class Treap
{
public:
Treap(int n);
void insert(T num);
void del(T num);
int lower_bound(T num); //返回大于等于x的第一个位置
int upper_bound(T num); //返回大于x的第一个位置
T at(int pos); //求第pos小的的值
int size();
}
二分查找
lower_bound与upper_bound这两个函数真的是非常经典了,基本可以适用于所有的查找情况,注意位置都是从1开始的。
- upper_bound实现
lower_bound(x+1)
- 求元素的出现次数
upper_bound(x)-lower_bound(x)
- 求元素是否出现
upper_bound(x)!=lower_bound(x)
- 求前驱(第一个小于给定值x的数)
at(lower_bound(x)-1)
- 求后继(第一个大于给定值x的数)
at(upper_bound(x))
- 查排名(比给定值小的个数+1)
lower_bound(x)
实现
实现细节请看之前写的Treap原理
template <typename T>
class Treap
{
vector<int> l,r,p,m,b; //左子树,右子树,随机权重,下辖数字个数,本值出现次数
vector<T> v;
int root,id,sz;
void lturn(int &rt) //左旋
{
int nrt = r[rt];
r[rt] = l[nrt];
l[nrt] = rt;
m[nrt] = m[rt];
m[rt] = m[l[rt]] + m[r[rt]] + b[rt];
rt = nrt;
}
void rturn(int &rt)
{
int nrt = l[rt];
l[rt] = r[nrt];
r[nrt] = rt;
m[nrt] = m[rt];
m[rt] = m[l[rt]] + m[r[rt]] + b[rt];
rt = nrt;
}
void insert(int &rt , T num)
{
if(rt == 0)
{
id++;
rt = id;
v[rt] = num;
m[rt] = b[rt] = 1;
p[rt] = rand();
return;
}
m[rt]++;
if(num == v[rt])
b[rt]++;
else if(num > v[rt])
{
insert(r[rt], num);
if(p[r[rt]] > p[rt]) lturn(rt);
}
else
{
insert(l[rt], num);
if(p[l[rt]] > p[rt]) rturn(rt);
}
}
void del(int &rt, T num)
{
if(rt == 0) return;
if(v[rt] == num)
{
if(b[rt] > 1)
b[rt]--, m[rt]--;
else if(l[rt] * r[rt] == 0)
rt = l[rt] + r[rt];
else if(p[l[rt]] < p[r[rt]])
lturn(rt), del(rt, num);
else
rturn(rt), del(rt, num);
}
else if(num > v[rt])
m[rt]--, del(r[rt], num);
else
m[rt]--, del(l[rt], num);
}
int lower_bound(int rt, T num)
{
if(rt == 0) return 1;
if(num == v[rt])
return m[l[rt]] + 1;
else if(num > v[rt])
return m[l[rt]] + b[rt] + lower_bound(r[rt], num);
return lower_bound(l[rt], num);
}
T at(int rt, int rank)
{
if(rt == 0) return 0;
if(rank <= m[l[rt]])
return at(l[rt], rank);
rank -= m[l[rt]];
if(rank <= b[rt])
return v[rt];
return at(r[rt], rank - b[rt]);
}
public:
Treap(int n)
{
root = id = sz = 0;
l = vector<int>(n+1);
r = vector<int>(n+1);
p = vector<int>(n+1);
m = vector<int>(n+1);
b = vector<int>(n+1);
v = vector<T>(n+1);
}
inline void insert(T num){sz++;return insert(root, num);}
inline void del(T num){sz--;return del(root, num);}
inline int lower_bound(T num){return lower_bound(root, num);}
inline int upper_bound(T num){return lower_bound(root, num+1);}
inline T at(int pos){return at(root, pos);}
inline int size(){return sz;}
};
模板题 Luogu P3369 普通平衡树
int main(void)
{
int n = read();
Treap<int> tr(n);
while(n--)
{
int op = read(), num = read();
if(op==1)
tr.insert(num);
else if(op==2)
tr.del(num);
else if(op==3)
printf("%d\n",tr.lower_bound(num));
else if(op==4)
printf("%d\n",tr.at(num));
else if(op==5)
printf("%d\n",tr.at(tr.lower_bound(num)-1) );
else
printf("%d\n",tr.at(tr.upper_bound(num)) );
}
return 0;
}