平衡树(Treap)

平衡树(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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值