ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

平衡树Splay与FHQ

2022-08-23 01:31:43  阅读:69  来源: 互联网

标签:rotate int tree 儿子 Splay 父亲 平衡 now FHQ


树剖的未来会补的(卑微)。

这里想讲讲平衡树,因为看着高级,可以证明我学过OI。

我们先了解下 \(BST\),也就是平衡二叉树。

他的概念是,对于每一个非叶子结点,他的左儿子一定小于当前节点,右儿子必定大于当前节点。

类似于如下图,就是一个好看的 \(BST\):

image

那我们现在对平衡二叉树有了深入的了解了,我们就开始进行平衡树的讲解。

一:平衡树解决的问题类型:

1.插入(删除)一个数

2.查询某个数的排名

3.查询某个排名所对应的数

4.查询某个数的前驱(后驱)

二:Splay

1.rotate 操作

分为左旋和右旋,我们偷一张图看一下:

image

我们将 x 右旋,就是将 x 的父亲 (y) 变成 x 的右儿子,x 的右儿子变成 y 的左儿子,x 变为 R 的右儿子。

我们将 y 左旋,得到的结果和上面一样。

那么我们可以轻松写出 rotate 函数了:

inline void rotate(int x) {
	int idx = check(x);//x作为y的哪个儿子
		int f = tree[x].f, idf = check(f);//y和y作为R的哪个儿子
		int sonx = tree[x].son[idx ^ 1];//x的儿子(与x作为的儿子反着)
		int ff = tree[f].f;//y的父亲
		
		connect(sonx, f, idx);//将x的儿子变成y的儿子
		connect(f, x, idx ^ 1);//将x的父亲变成x的儿子
		connect(x, ff, idf);//将x变为原来y的父亲的对应儿子
		
		update(f);
		update(x);//修改当前节点子树的大小
}

2.splay 函数

Splay 的核心,不然也不配命名为 splay。

主要就是进行旋转,将 u 转到 v 的上。

那么我们分三种情况:

1.v 是 u 的父亲,如下图:

image

我们只需要将 u 转一下即可:

image

2.u 作为 u 的父亲 k 的左(右)儿子, k 也作为 k 的父亲 v 的左(右)儿子,如下图:

image

我们需要先旋转 k,再旋转 u:

image

3.u 作为 u 的父亲 k 的左(右)儿子, k 也作为 k 的父亲 v 的右(左)儿子,如下图:

image

我们需要连选 2 次 u:

image

那么这样,我们可以很容易得到 splay 函数的代码:

inline void splay(int u, int v) {
	int fv = tree[v].f;
		
	while (fv != tree[u].f) {
		int fu = tree[u].f;
			
		if (fv == tree[fu].f) rotate(u);//v的父亲是u的父亲的父亲,即v是u的父亲		
		else if (check(u) == check(fu)) rotate(fu), rotate(u);//u和u的父亲分别同属于他们父亲的同种儿子
		else rotate(u), rotate(u);//与上面相反
	}
}

3.处理操作

1.插入:

那么是很显然的,只需要判断是否是相同的数即可。

相同的数,直接在频率上加一即可,否则建立新节点。

代码如下:

inline int add(int x, int fa) {
	tree[++ siz].data = x;
	tree[siz].f = fa;
	tree[siz].cnt = tree[siz].sum = 1;

	return siz;
}//添加一个节点

void push(int x) {
	int sign = 0, nxt;

	tot ++;

	if (! root) root = add(x, 0);//总得先有根节点吧……
	else {
		int now = root;

		while (now) {
			tree[now].sum ++;

			if (tree[now].data == x) {
				tree[now].cnt ++, sign = now;

				break; 
			} //已经有过这个数字,就将cnt++,位置标记

			nxt = tree[now].data < x ? 1 : 0;

			if (! tree[now].son[nxt]) {
				sign = tree[now].son[nxt] = add(x, now);

				break;
			}//这个节点还没有数字,就将这个数字差到当前节点

			now = tree[now].son[nxt];
		}
	}

	splay(sign, root);
}

2.删除:

标签:rotate,int,tree,儿子,Splay,父亲,平衡,now,FHQ
来源: https://www.cnblogs.com/fogleaf/p/16614769.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有