平衡树(Treap)
记一下平衡树模板
题目链接:
AcWing 253. 普通平衡树
洛谷 P3369 【模板】普通平衡树
Treap是树和堆的结合,以BST的特性维护数据的有序,以Heap的特性利用随机生成的dat来保持整棵树的基本平衡
需要注意的是处处记得更新维护,以及switch的局部变量作用域问题(参考error: jump to case label)
自己运行时,N没法开多大
其他都在注释里了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define N 100005
#define INF 1e9
struct Node
{
int l, r;
int val, dat, cnt, size;
//值,随机生成用来保持平衡的值,这个节点代表值的个数,子树大小
};
struct Treap
{
//val值左孩子<父节点<右孩子
//dat值父节点>子节点(堆的特性)
int tot, root;
Node t[N];
void Build()//新建树
{
tot = 0;
root = NewNode(-INF);
t[root].r = NewNode(INF);
Update(root);
//先加个边界,防止找前驱后继或没节点时的边界问题
}
int NewNode(int val)
{
tot++;
t[tot].val = val;
t[tot].dat = rand();
t[tot].cnt = t[tot].size = 1;
return tot;
}
void Update(int p)
{
t[p].size = t[t[p].l].size + t[t[p].r].size + t[p].cnt;
//左子树大小+右子树大小+节点大小
}
void Zig(int &p)//右旋
{
int q = t[p].l;
t[p].l = t[q].r;
t[q].r = p;
p = q;
Update(t[p].r), Update(p);//记得更新
}
void Zag(int &p)//左旋
{
int q = t[p].r;
t[p].r = t[q].l;
t[q].l = p;
p = q;
Update(t[p].l), Update(p);
}
void Insert(int &p, int val)
{
if (!p)
{
p = NewNode(val);
return;
}
if (val == t[p].val)
t[p].cnt++;
else if (val < t[p].val)
{
Insert(t[p].l, val);
if (t[t[p].l].dat > t[p].dat) Zig(p);
//左子树有变化,用dat判断是否失衡
}
else
{
Insert(t[p].r, val);
if (t[t[p].r].dat > t[p].dat) Zag(p);
}
Update(p);
}
void Delete(int &p, int val)
{
if (!p) return;//值不存在
if (val == t[p].val)
{
if (t[p].cnt > 1)//有多个可以直接减一
{
t[p].cnt--;
Update(p);
}
else if (t[p].l || t[p].r)//有孩子,转到下面去删除
{
if (!t[p].r || t[t[p].l].dat > t[t[p].r].dat)
{
//把左边转上来,删右边
Zig(p);
Delete(t[p].r, val);
}
else
{
Zag(p);
Delete(t[p].l, val);
}
Update(p);
}
else p = 0;//只能把这个节点删除
return;
}
if (val < t[p].val) Delete(t[p].l, val);
else Delete(t[p].r, val);
Update(p);//只要变了不忘更新
}
int Pre(int val)
{
int p = root, pre;
while (p)//一直走到底
{
if (t[p].val < val)//值小于val,应该往大的走
{
pre = t[p].val;
p = t[p].r;
}
else p = t[p].l;//等于或小于val都不满足条件,往小走
}
return pre;
}
int Next(int val)
{
int p = root, next;
while (p)
{
if (t[p].val > val)
{
next = t[p].val;
p = t[p].l;
}
else p = t[p].r;
}
return next;
}
int Rank(int p, int val)//求val在子树p中的排名
{
if (!p) return 0;
if (val == t[p].val)
return t[t[p].l].size + 1;//左子树的都更小
if (val < t[p].val)
return Rank(t[p].l, val);//在左子树里求rank
return Rank(t[p].r, val) + t[t[p].l].size + t[p].cnt;//左子树和本节点都更小,加上在右子树的rank
}
int Val(int p, int rank)//求子树p中排名为rank的值
{
if (!p) return INF;//不存在
if (rank <= t[t[p].l].size)
return Val(t[p].l, rank);
if (rank <= t[t[p].l].size + t[p].cnt) return t[p].val;
return Val(t[p].r, rank - t[t[p].l].size - t[p].cnt);//在右子树里找
}
void Print(int p)
{
if (!p) return;
Print(t[p].l);
cout << t[p].val << ' ';
Print(t[p].r);
}
};
int main()
{
Treap t;
t.Build();
int n;
cin >> n;
int op, val;
while (n--)
{
cin >> op >> val;
switch(op)
{
case 1:
t.Insert(t.root, val);
break;
case 2:
t.Delete(t.root, val);
break;
case 3:
cout << t.Rank(t.root, val) - 1 << endl;//因为有-INF
break;
case 4:
cout << t.Val(t.root, val + 1) << endl;//同理
break;
case 5:
cout << t.Pre(val) << endl;
break;
case 6:
cout << t.Next(val) << endl;
break;
/*
default:
cout << "不存在此操作,请重新输入:\n";
n++;
*/
}
//t.Print(t.root);
//cout << endl;
}
return 0;
}