# 平衡树( FHQtreap)——题目:普通平衡树

# 4月6日

参考代码(插入——分裂与合并):


inline void ins(int val){
	//分裂 
	split(root , val , x , y);
	root = merge(merge(x , newcode(val)) , y);
}

void split(int now , int val , int &x , int &y){
 //按值分裂 :val 就是分裂的标准 
	if(!now) x = y = 0;
	else{
		//二叉搜索树, 
		if(fhq[now].val <= val){
			x = now;
			split(fhq[now].r , val , fhq[now].r , y);
		} 
		else{
			y = now;
			split(fhq[now].l , val , x , fhq[now].l);
		}
		update(now);
	}
}

inline void update(int now){
	fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1 ; 
}

//和左偏树一样的合并操作
int merge(int x , int y){
	if(!x || !y) return x + y;
	if(fhq[x].key > fhq[y].key){
		fhq[x].r = merge(fhq[x].r , y);
		update(x);
		return x;
	}else{
		fhq[y].l = merge(x , fhq[y].l);
		update(y);
		return y;	
	}
}

今天继续
请教了一下大佬(也许昨天我就要这么干的),再来模拟一次:
看下流程图:
这是情况一:树会偏向一边,
在这里插入图片描述
……有时间再补QAQ

# 4月10日

题目:普通平衡树
虽然是抄的,但我觉得蛮不错的……
自己打还是很难……
那个笔记不能上传真的很难受……

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int cnt , root;
int x, y, z;
struct node{
	//左右子树,赋予的值val,堆排序关键字key,树上的高度; 
	int l , r , val , key , size;
}fhq[N];

inline int newcode(int val){
	fhq[++cnt].val = val;
	fhq[cnt].key = rand();
	fhq[cnt].size = 1; 
	return cnt;
}
void update(int now) {
	fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1;
}
void split(int now, int val, int &x, int &y) {
	//为空,就将带来的x,y赋值为0有两个作用.
	//其中一个是断开两个子树,另一个则是保留当前节点不存在的事实 
	if(!now) x = y = 0;
	else {
		//val满足二叉查找树
		//当前节点的val<=val,赋值x,向右找更大的y.
		if(fhq[now].val <= val) {
			//这里的x的意义是x或者当前节点,要注意 
			x = now;
			split(fhq[now].r, val, fhq[now].r, y); 
		}
		else {
			//当前节点的val>val,赋值x,向左找更小的x.
			y = now;
			split(fhq[now].l, val, x, fhq[now].l);
		}
		update(now);
	}
}
int merge (int x, int y) {
	// 随便什么堆的合并 
	if(!x || !y) return x + y;
	//这里的">"可以随便改,不会有影响.
	if(fhq[x].key > fhq[y].key) {
		fhq[x].r = merge(fhq[x].r, y);
		update(x);
		return x;
	}
	else {
		//merge中x.val是严格小于y.val的 
		fhq[y].l = merge(x, fhq[y].l);
		update(y);
		return y;
	}
}
void ins(int val) {
	split(root, val, x, y);
	//merge会返回合并后的根节点。 
	root = merge(merge(x, newcode(val)), y);
}

void del(int val) {
	//先裂开成x、x + n两棵子树 
	split(root, val, x, z);
	//然后是x - n, x 
	split(x, val - 1, x, y);
	y = merge(fhq[y].l, fhq[y].r);
	root = merge(merge(x, y), z);
}
//排名:排名定义为比当前数小的数的个数 +1 
void getrank(int val) {
	split(root, val - 1, x, y);
	printf("%d\n", fhq[x].size + 1);
	root = merge(x, y);
}
//查询排名为 x 的数
void getnum(int rank) {
	int now = root;
	while(now) {
		if(fhq[fhq[now].l].size + 1 == rank) break;
		//序号rank在左边 
		else if(fhq[fhq[now].l].size >= rank) now = fhq[now].l;
		//rank在右边,由于在右边序号会减小,所以要将右子树前面的点数删去 
		else {
			rank -= fhq[fhq[now].l].size + 1;
			now = fhq[now].r;
		}
	}
	printf("%d\n", fhq[now].val);
}

void pre(int val) {
	//先按照对应的值分开,找左子树的最右边那个点
	split(root, val - 1, x, y);
	int now = x;
	while(fhq[now].r) now = fhq[now].r;
	printf("%d\n", fhq[now].val);
	//记得合并回来 
	root = merge(x, y);
} 
void nxt(int val) {
	split(root, val, x, y);
	int now = y;
	while(fhq[now].l) now = fhq[now].l;
	printf("%d\n", fhq[now].val);
	root = merge(x, y);
} 
int main() {
	int n; cin >> n;
	for(int i = 1; i <= n; i ++) {
		int op, x; cin >> op >> x;
		if(op == 1) ins(x);
        if (op==2) del(x);
        if (op==3) getrank(x);
        if (op==4) getnum(x);
        if (op==5) pre(x);
        if (op==6) nxt(x);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值