首页 > 其他分享 >【博客】替罪羊树

【博客】替罪羊树

时间:2024-03-19 16:36:51浏览次数:29  
标签:return int 替罪羊 tr 博客 ls siz

替罪羊树

前言

暴力即优雅

替罪羊树是一种依赖于暴力重构操作维持平衡的平衡树

它利用了一个平衡因子\(α\)来维持平衡

\(α\)通常设0.7

当一棵子树不满足平衡因子的条件的时候

我们就把这棵子树拍扁重建

听起来就很暴力

在别人嗷嗷乱转的时候直接一巴掌上去

一打一个不吱声

感谢xixi的代码

平衡树(FHQ/Splay/替罪羊)

操作

重构

替罪羊树之所以能够平衡,是在于其重构时不是瞎重构,而是将被重构的子树重构为一棵完全二叉树

需要一个辅助的数组记录中序遍历的序列

int rebuild(int l,int r)
{
	if(l==r)
	{
		tr[t[l]]={tr[t[l]].v,1,1,1,0,0};
		return t[l];
	}
	int mid=l+r>>1;
	while(mid<r && tr[t[mid]].v==tr[t[mid+1]].v) mid++;
	int x=t[mid];
	ls(x)=l<mid?rebuild(l,mid-1):0;
	rs(x)=r>mid?rebuild(mid+1,r):0;
	tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;
	tr[x].fac=tr[ls(x)].fac+tr[rs(x)].fac+1;
	return x;
}

检查平衡

检查左右子树之一的大小占其本身子树大小的比例是否超过 \(α\)

如果不平衡就拍扁重建

image

就像这种 是不是看起来就欠拍不平衡

void check(int &x,int ed)
{
	if(x==ed) return;
	if(max(tr[ls(x)].siz,tr[rs(x)].siz)>tr[x].siz*0.7 || tr[x].siz-tr[x].fac>tr[x].siz*0.3)
	{
		t.clear();
		dfs(x);
		x=t.empty()?0:rebuild(0,t.size()-1);
        return;
	}
	check(tr[x].s[tr[ed].v>tr[x].v],ed);
	tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;
}

插入

替罪羊树的插入操作与其他的二叉搜索树差不多。

只不过因为其导致了树形态的改变

我们在插入完回溯的过程中还需要判断一下是否需要重构

void Insert(int &x,int v)
{
	if(!x)
	{
		tr[x=++cnt]={v,1,1,1};
		check(rt,x);
		return;
	}
	tr[x].siz++,tr[x].fac++;
	Insert(tr[x].s[v>tr[x].v],v);
}

删除

替罪羊树使用惰性删除(就是打标记删),只需要将对应节点上代表节点内数据数量的标记自减一即可。

void delet(int x,int v)
{
	tr[x].fac--;
	if(tr[x].fg && tr[x].v==v)
	{
		tr[x].fg=0;
		check(rt,x);
	}
	else delet(tr[x].s[v>tr[x].v],v);
}

查询

跟BST相同

判断该找左子树还是右子树

递归找即可

int getrank(int v)
{
	int x=rt,k=1;
	while(x)
	{
		if(v<=tr[x].v) x=ls(x);
		else k+=tr[x].fg+tr[ls(x)].fac,x=rs(x);
	}
	return k;
}
int getval(int k)
{
	int x=rt;
	while(x)
	{
		if(tr[x].fg && tr[ls(x)].fac+tr[x].fg==k) break;
		if(tr[ls(x)].fac>=k) x=ls(x);
		else k-=tr[ls(x)].fac+tr[x].fg,x=rs(x);
	}
	return tr[x].v;
}

有了之前的基础

感觉平衡树越来越好学

再次感谢xixi的代码

(号称全网最佳)

完结撒花


引用来源

替罪羊树~讲解

替罪羊树(Scapegoat Tree)-CSDN博客

替罪羊树 - OI Wiki (oi-wiki.org)

标签:return,int,替罪羊,tr,博客,ls,siz
From: https://www.cnblogs.com/zysssss/p/18083281

相关文章

  • 【博客】CDQ分治
    CDQ分治前言CDQ分治是一种分治CDQ分治是一种特殊的分治思想可以用于跟点对有关的问题还有其他用处......(目前不会)算法流程一般来说,cdq分治是通过如下结构进行分治一共分为三步:找到当前区间\([l,r]\)中点\(mid\)递归处理左右区间\([l,mid]\),\([mid+1,r]\)计算左区间......
  • 【博客】顺序结构
    顺序结构概念程序设计要从最简单的地方开始学习,由浅入深,直至掌握。所以要重视基础训练。我们编写计算机程序,将一个任务分解成一条一条的语句,计算机会按照顺序一条一条的执行这些语句,这就是顺序结构程序设计。举个栗子:老师给你留了寒假作业,你现在要一项一项地完成,于是你写下......
  • 【博客】分块
    分块前言顾名思义分块就是将要维护的数据分成多个块来进行操作涉及整块的直接在块上操作涉及块中的暴力操作暴力即优雅分块是在线算法一般跟区间有关系算法如果一个序列长度为\(n\)我们一般取\(\sqrt{n}\)为一个块的长度这样块的数量也是\(\sqrt{n}\)原理如下设......
  • 【博客】左偏树
    左偏树前言左偏树是一棵向左偏的树左偏树是一种能在\(O(\logn)\)之内完成合并的可并堆长这样我们常用左偏树完成以下操作在指定集合中插入一个元素查询集合中最高优先级的元素删除集合中最高优先级的元素删除指定元素合并两个集合性质首先我们要知道左偏树的......
  • 【博客】K-D树
    K-D树前言kd-tree(k-dimensional树的简称),是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)好像跟没说一样K-D树其实是每个结点为K维数值点的二叉树每个结点将某一维划分成两部分一部分为左......
  • 【博客】【入门级】递归
    递归有部分结论代码题目来自网络在文后有链接侵删前言什么是递归?函数反复调用自身即是递归举个栗子递归我在这篇博客里写了这篇博客的链接像不像套娃举个正经栗子比如我们算\(n\)的阶乘\(f(n)\)(阶乘就是\(1*2*3*4*...*n\))以\(f(6)\)为例\(f(6)\)=>\(6\)*$......
  • 新电脑 个人博客迁移
    安装和配置所需要的软件安装Git客户端,安装过程省略,一般默认下一步    下载地址:Git客户端    这个无脑下一步即可无需配置安装nodeJS,安装过程省略,一般默认下一步    下载地址:nodeJS    配置看这位大佬教程:地址拷贝个人博客文件夹中,部......
  • 将博客搬至CSDN
    New·Object将博客搬至CSDN在数字时代的浪潮中,我始终如一地维护着自己的一方网络空间。从最初的个人网站到现在的CSDN博客,每一次的变迁都记录着我的成长与变化。今天,我想和大家分享一下将博客搬迁至CSDN的决定背后的故事,以及这个决定给我带来的一系列连锁反应。记得最初,我的博......
  • 推荐一个博客园皮肤:awescnb-theme-geek
    参考文章:我的所有做法都是参考本篇文章1.安装主题首先进入到博客后台设置:1.设置皮肤为customer,并且打开JS权限2.勾选禁用模板默认CSS3.复制粘贴配置代码(共三处)页面定制CSS代码#loading{bottom:0;left:0;position:fixed;right:0;top:0;z-index:9999;background-co......
  • 初出茅庐的小李博客之串口屏开发一个音乐控制器UI
    串口屏介绍串口屏通常指的是一种带有串口接口的显示屏,可以通过串口与其他设备进行通信和控制。这种屏幕通常具有独立的控制器和显示功能,可以直接接入主控系统,实现信息的显示和交互。开发步骤准备UI素材准备了100张音量的图标,这里面还遇到了个小问题,这么多图片如何批量......