首页 > 其他分享 >学习笔记:旋转treap

学习笔记:旋转treap

时间:2024-12-29 19:42:51浏览次数:1  
标签:ch val int 笔记 旋转 treap ls now dir

前言

更好的阅读体验
无旋 treap。
默认读者会 BST 的基本操作、堆和旋转
本文旋转部分和上面那篇文章的相同。
代码中是小根堆。

思想

treap 既是一棵二叉查找树(tree),也是一个二叉堆(heap)。
但是如果这两个数据结构用同一个权值维护,那么这两种数据结构是矛盾的。
所以 treap 用了一个很巧妙的方式:给每个节点附加一个随机的优先级,让权值满足二叉查找树的结构,让优先级满足二叉堆的结构。
这个就是一棵 treap(黑色是权值,蓝色是随机的优先级):
tu
由于优先级只能随机赋予,堆不一定是一颗完全二叉树,,所以 treap 是弱平衡(近似平衡)的。

旋转

在不改变中序遍历的情况下,旋转可以改变树的结构。
在 treap 中,我们用旋转来满足二叉堆,控制树高。
图中从左到右是右旋,从右到左是左旋。
tu
我们来模拟一下右旋的过程(左旋同理)。
tu
在实现中,我会把左右旋放在一起写。

void rotate(int&now, int dir){  
    int t = d[now].ch[dir];  
    d[now].ch[dir] = d[t].ch[!dir];  
    d[t].ch[!dir] = now;  
    pushup(now), pushup(t), now = t;  //now 是 t 的儿子了,先更新 now 再更新 t
}  

这里的 rotate(x, 0) 表示将 \(ls_{x}\) 提到 \(x\) 的高度,即右旋。
这里的 rotate(x, 1) 表示将 \(rs_{x}\) 提到 \(x\) 的高度,即左旋。

基础操作

节点变化

我们要在定义的时候添加一个优先级,然后在新建时给他赋随机值。

//需要头文件 <random>,<chrono>    
std::mt19937 rd(std::chrono::steady_clock::now().time_since_epoch().count());  
struct node{  
    int ch[2], size, val, rank;  
}d[N];  
int newnode(int x){  
    int w = ++tot;  
    d[w].val = x, ls(w) = rs(w) = 0, d[w].size = 1, d[w].rank = rd();  
    return w;  
}  

插入

只有在插入的那个子树的优先级可能变化。
如果优先级比当前节点小,那么我们把它旋转上来。
记得更新节点。

void insert(int&now, int val){  
    if(!now)return void(now = newnode(val));  
    int dir = d[now].val < val;  
    insert(d[now].ch[dir], val);  
    if(d[d[now].ch[dir]].rank < d[now].rank)rotate(now, dir);  
    if(now)pushup(now);  
}  

删除

这里我们需要改变一下目标节点有两个儿子的时候的方法。
我们比较两个儿子的优先级,把优先级小的旋转上来。
那么目标节点就到当前节点的另一侧,继续删除即可。
返回时要更新节点。

void del(int&now, int val){  
    if(!now)return;  
    if(d[now].val == val){  
        if(ls(now) && rs(now)){  
            int z = d[rs(now)].rank < d[ls(now)].rank;//哪边的优先级小  
            rotate(now, z), del(d[now].ch[!z], val);//删除另一侧  
        }  
        else now = ls(now) ? ls(now) : rs(now);  
    }  
    else if(d[now].val < val)del(rs(now), val);  
    else del(ls(now), val);  
    if(now)pushup(now);//牢记  
}  

代码

P3369

可持久化

不知道什么是可持久化的戳
只需要在所有要修改节点的地方新建节点,有注释的是新加句子。
完整代码
修改片段:

void copynode(int &i){if(i)d[++tot] = d[i], i = tot;}//************  
void rotate(int&now, int dir){  
		int t = d[now].ch[dir];  
		copynode(t);//**************  now节点已经新建过了
        d[now].ch[dir] = d[t].ch[!dir];  
        d[t].ch[!dir] = now;  
        pushup(now), pushup(t), now = t;  
	}  
	void insert(int&now, int val){  
		copynode(now);//****************  
		if(!now)return void(now = newnode(val));  
		int dir = d[now].val < val;  
		insert(d[now].ch[dir], val);  
		if(d[d[now].ch[dir]].rank < d[now].rank)rotate(now, dir);  
		if(now)pushup(now);  
	}  
	void del(int&now, int val){  
		copynode(now);//****************  
		if(!now)return;  
		if(d[now].val == val){  
			if(ls(now) && rs(now)){  
				int z = d[rs(now)].rank > d[ls(now)].rank;  
				rotate(now, z), del(d[now].ch[!z], val);  
			}  
			else now = ls(now) ? ls(now) : rs(now);  
		}  
		else if(d[now].val < val)del(rs(now), val);  
		else del(ls(now), val);  
		if(now)pushup(now);  
	}  

标签:ch,val,int,笔记,旋转,treap,ls,now,dir
From: https://www.cnblogs.com/fush/p/18639440

相关文章

  • 异或线性基学习笔记
    更好的阅读体验。前言本文的线性基指异或线性基。由于作者太菜了本文的语言不会特别规范。简介线性基简称基,它是一个数的集合,并且每个序列都拥有至少一个线性基。线性基有三个性质:线性基中的几个数异或后不能得到\(0\)。线性基中的数在异或后能得到原序列中的所有数。......
  • 浅析FHQ-treap
    前言更好的阅读体验默认读者会BST的基本操作。节点定义替罪羊树采用了懒惰删除的方法,不会立即删除某个点,而是在重构时不放进数组。structnode{intch[2],val;intsiz1,siz2,cnt,sum;//扣去懒惰删除的节点数量,没扣去懒惰删除的节点数量,树内相同权......
  • Open Notebook:开源 AI 笔记工具,支持多种文件格式,自动转播客和生成总结,集成搜索引擎等
    ❤️如果你也关注AI的发展现状,且对AI应用开发非常感兴趣,我会每日跟你分享最新的AI资讯和开源应用,也会不定期分享自己的想法和开源实例,欢迎关注我哦!......
  • 《程序员修炼之道:从小工到专家》阅读笔记
    一、重视基础知识书中强调了基础知识的重要性。如同盖房子,坚实的地基才能撑起高楼大厦。对于程序员来说,像数据结构、算法等基础知识是解决复杂问题的基石。例如在处理大量数据排序时,若熟悉不同排序算法的原理和时间复杂度,就能选择最合适的算法,提高程序效率。二、注重代码质量代......
  • 亚里士多德《形而上学》第7卷第7节阅读笔记
    亚里士多德的《形而上学》以其晦涩难懂著称。读英文稍微能理解一点,中文翻译完全看不懂。但是作为母语中文的读者,读英文虽然字面意思能看懂,却难以记忆和反思。这里我自己从JonathanBarnes编辑的英译本(W.D.Ross翻译的)自行翻译了一些要点为中文,方便理解。 7、8、9节都是围绕“生......
  • 折腾笔记[3]-迁移U盘的ubuntu到虚拟机
    摘要使用clonezilla工具迁移安装到U盘中的ubuntu18.04系统到vmware虚拟机.关键信息clonezillaubuntu18.04cpu:x86_64vmware:17.6.0ubuntu引导方式:UEFI+GRUB2windows11原理简介clonezilla简介[https://clonezilla.org/][https://linux.cn/article-3888-1.html]再......
  • ♂hook♂学习笔记~(持续更新)
    主要是从攻防世界中的easyhook中学习,感觉好神奇.参考了以下博客:攻防世界逆向高手题之EASYHOOK-CSDN博客RE套路/从EASYHOOK学inlinehook-c10udlnk-博客园先贴源码:sub_401370(aPleaseInputFla);scanf("%31s",input_flag);if(strlen(input_flag)==19)......
  • 2024-12-13《构建之法阅读笔记》
    构建之法阅读笔记(1) 第一章概论在这一章中,作者为我们介绍了一些关于软件工程的基本知识。①软件=程序+软件工程:正是因为对软件开发活动(构建管理、源代码管理、软件设计、软件测试、项目管理)相关的内容的完成,才能完成把整个程序转化成为一个可用的软件的过程。扩展的推论......
  • C语言学习笔记(基础语法篇)
    C语言学习笔记(基础语法篇)序言首先事先说明一下,这是我从各处整理的,当初刚接触CS,甚至连标注意识都没有,再次感谢写这些文章的人.当然这里不是说全部都是别人写的了,也有一点我自己的思考.首先是几个注意点:结构化,模块化,分而治之多写注释,多调试指针也有不同类型......
  • PYTHON语言学习笔记(基础语法篇)
    Python学习笔记序言主要是以小甲鱼的视频为主,https://space.bilibili.com/314076440一些特性多次调用方法是从左到右.而参数是函数则先执行参数.一行如果要多个赋值,用;隔开input().split()IO看我放在另一个地方的文档.<D:\Document\md\PYTHON\IO.md>数据类型变量没什......