模板 - treap平衡树

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
#define fixed(s) fixed<<setprecision(12)<<s
//#define int long long
 
using namespace std;
 
typedef pair<int, int> PII;
typedef long long ll;

const int N = 100010, INF = 1e8;

int root, idx;
struct Node
{
	int l, r;//左孩子、右孩子 
	int key, val;//存储的值 和 维持平衡的堆 
	int cnt, size;//当前数的个数、当前子树总共多少个数
}tr[N];

void pushup(int p)
{
	tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + tr[p].cnt;
}

int get_node(int key)
{
	int p = ++ idx;
	tr[p].key = key;
	tr[p].val = rand();
	tr[p].cnt = tr[p].size = 1;
	return p;
}

void zig(int &p)
{
	int lchild = tr[p].l;
	tr[p].l = tr[lchild].r;
	tr[lchild].r = p;
	p = lchild;
	pushup(tr[p].r), pushup(p);//更新一下size 
}

void zag(int &p)
{
	int rchild = tr[p].r;
	tr[p].r = tr[rchild].l;
	tr[rchild].l = p;
	p = rchild;
	pushup(tr[p].l), pushup(p); 
}

void insert(int &p, int key)
{
	if(!p)p = get_node(key);//如果没有节点就先创建一个 
	else if(tr[p].key == key) tr[p].cnt ++;//size用pushup更新
	else if(key < tr[p].key)
	{
		insert(tr[p].l, key);
		if(tr[tr[p].l].val > tr[p].val)zig(p);//左孩子大,右旋一下 
	}
	else
	{
		insert(tr[p].r, key);
		if(tr[tr[p].r].val > tr[p].val)zag(p);//右孩子大,左旋一下 
	} 
	pushup(p);
}

void remove(int &p, int key) 
{
	if(!p)return;
	if(tr[p].key == key)
	{
		if(tr[p].cnt > 1)tr[p].cnt --;
		else if(tr[p].l || tr[p].r)
		{
			if(!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val)//要左边的比右边大,如果右边为空就没事 
			{
				zig(p);
				remove(tr[p].r, key);
			}
			else
			{
				zag(p);
				remove(tr[p].l, key);
			}
		}
		else p = 0; //直接删了这个点 
	}
	else if(key < tr[p].key)
	{
		remove(tr[p].l, key);
	}
	else remove(tr[p].r, key);
	pushup(p);
}

int get_rank_by_key(int p, int key)
{
	if(!p)return 0;
	if(tr[p].key == key)return tr[tr[p].l].size + 1;
	if(key < tr[p].key)return get_rank_by_key(tr[p].l, key);
	return tr[tr[p].l].size + tr[p].cnt + get_rank_by_key(tr[p].r, key);
}

int get_key_by_rank(int p, int rank)
{
	if(!p)return INF;
	if(tr[tr[p].l].size >= rank)return get_key_by_rank(tr[p].l, rank);
	if(tr[tr[p].l].size + tr[p].cnt >= rank)return tr[p].key;
	return get_key_by_rank(tr[p].r, rank - tr[tr[p].l].size - tr[p].cnt);
}

int get_prev(int p, int key)
{
	if(!p)return -INF;
	if(tr[p].key >= key)return get_prev(tr[p].l, key);
	return max(tr[p].key, get_prev(tr[p].r, key));
}

int get_next(int p, int key)
{
	if(!p)return INF;
	if(tr[p].key <= key)return get_next(tr[p].r, key);
	return min(tr[p].key, get_next(tr[p].l, key));
}
/*
void build()
{
    get_node(-INF), get_node(INF);
    root = 1, tr[1].r = 2;
    pushup(root);

    if (tr[1].val < tr[2].val) zag(root);
}
*/
int main()
{
	IOS
	//build();//菜菜园子说treap中无哨兵,以防万一加进板子里,如果要用哨兵的话最小值是-INF,查询时注意一下 
	int n;
	cin >> n;
	for(int i = 0; i < n; i ++)
	{
		int op, x;
		cin >> op >> x;
		if(op == 1)insert(root, x);
		else if(op == 2)remove(root, x);
		else if(op == 3)cout << get_rank_by_key(root, x) << endl;
		else if(op == 4)cout << get_key_by_rank(root, x) << endl;
		else if(op == 5)cout << get_prev(root, x) << endl;
		else cout << get_next(root, x) << endl;
	}
	
	return 0;
}

左旋、右旋:

         关于删除操作中左旋、右旋的问题。某个点旋一次就能降低一层,log次到达根节点,旋到根节点再删。旋的时候也要保证旋完以后保证这个val的大根堆性质,虽然旋完x这个点后x的val肯定比y的val要大,但是x这个点是要被删掉的点,所以暂时的不合法状态时没问题的,因为最后一定会变为合法状态。保证其它的点合法就行。

        总而言之,就是旋上去的点一定得是val值最大的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值