【学习笔记】fhq Treap实现文艺平衡树

这篇具有很好参考价值的文章主要介绍了【学习笔记】fhq Treap实现文艺平衡树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

没有学习过 fhq Treap 的可以看我上一篇文章,看过的建议去再看看分裂和合并操作

回顾

在上一篇文章中提到,fhq Treap 可以支持比较多的操作,文艺平衡树就是其中一种,其实就是可以实现区间操作(翻转)的平衡树

文艺平衡树

板子在这里

fhq Treap 实现文艺平衡树的步骤是:

  1. 将树按大小分裂成小于 l l l 和 大于等于 l l l 的两颗树
  2. 把大的那颗树再按 r − l + 1 r-l+1 rl+1 分裂掉
  3. 把得到的大小为 r − l + 1 r-l+1 rl+1 的树打上标记

这里用到了线段树懒标记的思想,没有学过线段树的看这里

不懂为什么按大小分裂可以的先别着急,接着往下看

push_up

和前面讲的是一样的,就不赘述了

void push_up(int pos){
	fhq[pos].siz = fhq[fhq[pos].l].siz + fhq[fhq[pos].r].siz + 1;
}

push_down

和线段树一样的,如果当前位置存在翻转,那就翻转掉,然后把标记下传到左右子树去,记得清空懒标记

这里使用异或,也就是原来翻转的现在不翻转了,原来不翻转的现在翻转了

void push_down(int pos){
	if(fhq[pos].tag){
		swap(fhq[pos].l,fhq[pos].r);
		fhq[fhq[pos].l].tag ^= 1;
		fhq[fhq[pos].r].tag ^= 1;
		fhq[pos].tag = 0;
	}
}

关于 push_down 放在哪里,在要修改当前节点的时候就下传,如果你分不清,还有一种方法是哪哪都放一个

分裂

这里是按照大小分裂,其实可以理解为按照 rank 分裂,因为如果画张图会发现,一开始的树的中序遍历其实就是原序列,所以按照大小其实就是按照原来的 rank 去把区间取出来再进行操作

个人感觉可以参考上一篇 查询排名为 rank 的值 这个函数来理解

void split(int pos, int siz , int &x, int &y){
	if(!pos){
		x = y = 0;
		return;
	}
	push_down(pos);
	if(fhq[fhq[pos].l].siz < siz){
		x = pos;
		split(fhq[pos].r,siz - fhq[fhq[pos].l].siz-1,fhq[pos].r,y);
	}else{
		y = pos;
		split(fhq[pos].l,siz,x,fhq[pos].l);
	}
	push_up(pos);
}

可能把 s i z siz siz 改成 r a n k rank rank 会更好理解一点?

合并

合并其实也就是多了个 push_down 其他没啥区别

int merge(int x, int y){
	if(!x || !y) return x+y;
	if(fhq[x].key < fhq[y].key){
		push_down(x);
		fhq[x].r = merge(fhq[x].r,y);
		push_up(x);
		return x;
	}else{
		push_down(y);
		fhq[y].l = merge(x,fhq[y].l);
		push_up(y);
		return y; 
	}
}

翻转

翻转直接按照上面说的步骤来就可以了

void reverse(int l, int r){
	int x,y,z;
	split(root,l-1,x,y);
	split(y,r-l+1,y,z);
	fhq[y].tag ^= 1;
	root = merge(merge(x,y),z);
}

输出

上面提到,没经过操作的树的中序遍历就是原序列,所以同理的,操作之后的树也输出中序遍历就可以了

void print(int pos){
	if(!pos) return;
	push_down(pos);
	print(fhq[pos].l);
	cout << fhq[pos].val << " ";
	print(fhq[pos].r);
}

Code

这里构造原序列的时候,因为有一个性质:序列是顺序的,所以后加入的节点一定比前面的节点都大,所以直接合并就可以了

#include <bits/stdc++.h>
const int N = 1e5+10;
using namespace std;
int n,m;
struct treap{
	int val,key,siz,l,r;
	bool tag;
}fhq[N];
int cnt,root;

int new_treap(int val){
	fhq[++cnt].val = val;
	fhq[cnt].siz = 1;
	fhq[cnt].key = rand();
	return cnt;
}
void push_up(int pos){
	fhq[pos].siz = fhq[fhq[pos].l].siz + fhq[fhq[pos].r].siz + 1;
}
void push_down(int pos){
	if(fhq[pos].tag){
		swap(fhq[pos].l,fhq[pos].r);
		fhq[fhq[pos].l].tag ^= 1;
		fhq[fhq[pos].r].tag ^= 1;
		fhq[pos].tag = 0;
	}
}
void split(int pos, int siz , int &x, int &y){
	if(!pos){
		x = y = 0;
		return;
	}
	push_down(pos);
	if(fhq[fhq[pos].l].siz < siz){
		x = pos;
		split(fhq[pos].r,siz - fhq[fhq[pos].l].siz-1,fhq[pos].r,y);
	}else{
		y = pos;
		split(fhq[pos].l,siz,x,fhq[pos].l);
	}
	push_up(pos);
}
int merge(int x, int y){
	if(!x || !y) return x+y;
	if(fhq[x].key < fhq[y].key){
		push_down(x);
		fhq[x].r = merge(fhq[x].r,y);
		push_up(x);
		return x;
	}else{
		push_down(y);
		fhq[y].l = merge(x,fhq[y].l);
		push_up(y);
		return y; 
	}
}
void reverse(int l, int r){
	int x,y,z;
	split(root,l-1,x,y);
	split(y,r-l+1,y,z);
	fhq[y].tag ^= 1;
	root = merge(merge(x,y),z);
}
void print(int pos){
	if(!pos) return;
	push_down(pos);
	print(fhq[pos].l);
	cout << fhq[pos].val << " ";
	print(fhq[pos].r);
}
int main(){
	srand(time(0));
	cin >> n>> m;
	for(int i = 1;i <= n; i++){
		root = merge(root,new_treap(i));
	}
	while(m--){
		int l,r;
		cin >> l >> r;
		reverse(l,r);
	}
	print(root);
	return 0;
}

有任何疑问或不足之处,欢迎在评论区指出文章来源地址https://www.toymoban.com/news/detail-688004.html

到了这里,关于【学习笔记】fhq Treap实现文艺平衡树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 平衡树学习笔记

    平衡树就是为了实现一类元素在线性结构中动态变化的功能所需要的数据结构。 平衡树是一种基于二叉搜索树的数据结构。 满足:左儿子 () 根 () 右儿子。 也就是一切小于根节点的在左边,一切大于根节点的在右边。 这样想要查找一个节点的位置时间复杂度就是 (O(log

    2024年02月03日
    浏览(20)
  • 「学习笔记」平衡树——splay 一

    Splay ,一种平衡树,同时也是二叉排序树,与 Treap 不同,它不需要维护堆的性质,它由 Daniel Sleator 和 Robert Tarjan(没错,tarjan,又是他)创造,伸展树是一种自调整二叉树,它会将一个节点沿着到根的路径旋转上去。 空间效率: (O_n) 摊平时间效率: (O_{logn}) 建议先学会

    2024年02月07日
    浏览(51)
  • 算法学习笔记(21): 平衡树(二)

    平衡树(一)链接:算法学习笔记(18): 平衡树(一) - jeefy - 博客园 本文中将讲述一下内容: 可持久化Treap 基于 Trie 的 类 平衡树(后文称之为 BSTrie ) BSTrie的可持久化 可持久化Treap基于FHQ-Treap。其实不难发现,FHQ-Treap在分裂和合并时在每一层只对一个结点产生影响。于是我

    2024年02月04日
    浏览(29)
  • Linux 基础入门(学习笔记通俗易懂版)

    本文章是学习了Linux的学习记录,着重记录了我对于Linux各命令的用法与感悟, 欢迎各位大佬批评指正 记录者:CYH-BI 记录日期:2023年7月7日 本篇文章将使用 虚拟机并安装centos 进行实操。关于虚拟机的安装请看其他教程,篇幅过长,不一展示。 Linux简介部分 Linux起初由Linus

    2024年02月08日
    浏览(39)
  • 如何学习网络安全?(零基础入门网络安全学习笔记)

    概括来说,网络安全课程的主要内容包括: 安全基本知识 应用加密学 协议层安全 Windows安全(攻击与防御) Unix/Linux安全(攻击与防御) 防火墙技术 入侵监测系统 审计和日志分析 下面分别对每部分知识介绍相应的具体内容和一些参考书。 一、安全基本知识 这部分的学习过

    2024年02月11日
    浏览(35)
  • STM32基础入门学习笔记:内部高级功能应用

    文章目录: 一:低功耗模式 1.睡眠模式测试程序 NVIC.h NVIC.c key.h key.c main.c 2.停机模式测试程序 main.c 3.待机模式测试程序 main.c 二:看门狗 1.独立看门狗测试程序 iwdg.h iwdg.c main.c 2.窗口看门狗测试程序 wwdg.h wwdg.c main.c 三:TIM定时器 tim.h tim.c main.c 四:CRC循环冗余校验计算单元与

    2024年02月13日
    浏览(29)
  • 古月居《ROS入门21讲》零基础学习笔记

    ”怕什么真理无穷,进一寸有一寸的欢喜。” ——古月 适 本人大一小白一枚,参加了一个本科生科研项目,目前正在学习一些ROS1相关的一些前置基础知识。 在这里以博客的形式记录一下学习的过程、操作的细节及操作的结果、爬坑方法、听课笔记。 希望能给同样在学习相

    2023年04月20日
    浏览(25)
  • web渗透安全学习笔记:1、入门基础知识/ XXS漏洞

        自编写python渗透工具编写学习笔记专栏以来,笔者便发现了一个较为严重的问题:我们大多数文章都是学习如何用python编写扫描与利用漏洞的渗透工具,却没有真正解析漏洞的形成原因,长此以往我们的学习就只会浮于表面,广而不深。为了改变这一现状,笔者决定以深

    2024年02月03日
    浏览(38)
  • STM32基础入门学习笔记:核心板 电路原理与驱动编程

    文章目录: 一:LED灯操作  1.LED灯的点亮和熄灭 延迟闪烁 main.c  led.c led.h BitAction枚举 2.LED呼吸灯(灯的强弱交替变化) main.c  delay.c 3.按键控制LED灯 key.h key.c main.c  二:FLASH读写程序(有记忆可以保存断电之前的状态) flash.h flash.c main.c flash操作注意事项 三:蜂鸣器驱动程序(

    2024年02月13日
    浏览(25)
  • 【UnityShader入门精要学习笔记】第六章(1)Unity中的基础光照

    本系列为作者学习UnityShader入门精要而作的笔记,内容将包括: 书本中句子照抄 + 个人批注 项目源码 一堆新手会犯的错误 潜在的太监断更,有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 一个物体为什么看起来是红色的?从物理上解释是因为这个物体

    2024年03月22日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包