首页 > 其他分享 >【理论】左偏树笔记

【理论】左偏树笔记

时间:2023-03-08 16:58:40浏览次数:36  
标签:一个点 理论 1000005 合并 笔记 左偏 ll dis

左偏树是可并堆的一种实现方法。

左偏,很容易形象地理解它是什么意思。

但对于一棵树,如何用形象和具体化的语言来描述左偏性质?

考虑定义 \(dis_i\) 表示 \(i\) 的子树中最近的空节点理 \(i\) 点的距离。

空节点是什么意思?由于左偏树是一棵二叉树,所以一个点没有左儿子/右儿子,其实可以看做其有一个左空儿子/右空儿子。

不难发现 \(dis_i\) 等价与 \(i\) 的子树往下拓展 \(1\sim dis_i-1\) 层都将是满二叉树,当拓展到 \(dis_i\) 层时其一定不是一棵满二叉树。

感性理解一下 \(dis_i\) 可以用来衡量一个点 \(i\) 的子树的茂密程度。

那么左偏的表示就呼之欲出了,\(dis_{ls}\ge dis_{rs}\),即左边比右边更茂密。

那么维护 \(dis\) 也变得十分方便,即 \(dis_x=dis_{rs}+1\)。

好了,左偏树的左偏性质搞好了,堆性质维护起来也很容易,关键是,其作为可并堆,如何合并?

类似 FHQ 与线段树合并,设一个 \(merge(x,y)\) 表示将 \(x,y\) 合并后的新节点。

每次 \(merge(x,y)\),我们将更小的点拿出来作为根(为了满足堆性质),然后将另外一个点与与更小的点的右儿子进行合并?

为什么是右儿子?因为我们再满足左偏条件下还要保证左右子树相对均匀。

那 \(merge\) 完了不再左偏了怎么办?交换一下左右子树即可。

这样合并就做完了。

删除一个点怎么做?

考虑直接合并该点的左右儿子即可。

那么就只差最后一步了,找某个点对应左偏树的根。

这看似轻松,实则不然,如果用朴素并查集,无法支持左偏树的删除操作,如果暴力跳的话,左偏树合并虽然是 \(O(\log n)\),可树高确是实打实的 \(O(n)\)。

考虑在左偏树上进行路径压缩,然后类似并查集那样不断 find,这么做的话,即使将一个点删掉,那么由于之前有的节点的路径压缩时指向的它,所以这个节点依然会在路径压缩中以另一种形式存在。

做完了。

代码
ll n,m,a[1000005],ls[1000005],rs[100005],fa[1000005],dis[1000005],f[1000005];
bool del[1000005];
ll find(ll x){return x==f[x]?x:f[x]=find(f[x]);}
bool cmp(ll x,ll y){return a[x]==a[y]?x<y:a[x]<a[y];}
void maintain(ll x){
	if(ls[x]) fa[ls[x]]=x;
	if(rs[x]) fa[rs[x]]=x;
	if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
	dis[x]=dis[rs[x]]+1;
	return;
}
ll merge(ll x,ll y){
	if(!x||!y) return x+y;
	if(cmp(y,x)) swap(x,y);
	rs[x]=merge(rs[x],y);
	maintain(x);
	return x;
}
int main(){
	rd(n);
	rd(m);
	rep(i,1,n){
		dis[i]=1;
		f[i]=i;
		rd(a[i]);
	}
	while(m--){
		ll opt;
		rd(opt);
		if(opt==1){
			ll x,y;
			rd(x);
			rd(y);
			if(del[x]||del[y]) continue;
			ll fx=find(x),fy=find(y);
			if(fx==fy) continue;
			f[fx]=f[fy]=merge(fx,fy);
		}
		else{
			ll x;
			rd(x);
			if(del[x]){
				puts("-1");
				continue;
			}
			ll fx=find(x);
			printf("%lld\n",a[fx]);
			del[fx]=1;
            dis[fx]=-1;
			fa[ls[fx]]=fa[rs[fx]]=0;
			f[fx]=f[ls[fx]]=f[rs[fx]]=merge(ls[fx],rs[fx]);
        }
	}
}

标签:一个点,理论,1000005,合并,笔记,左偏,ll,dis
From: https://www.cnblogs.com/Miracle-blog/p/17192595.html

相关文章

  • Excel基础学习笔记
    EXCEL快速填充:CTRL+E帮你合并拆分内容想用快速填充附近一定要有数据 快速分析数据:选中目标区域后直接CTRL+Q快速分析能实现多种效果:格式化、图标、汇总、表格、迷......
  • Python学习笔记:str.zfill补全位数
    一、介绍zfill函数用于在字符串的开头添加零,直到达到指定的长度。如果len参数的值小于字符串的长度,则不执行填充。具体使用语法为:str.zfill(len)如果是整型、浮点......
  • 知识点笔记
    CopyOnWriteArrayList的底层原理是怎样的?1. ⾸先CopyOnWriteArrayList内部也是⽤过数组来实现的,在向CopyOnWriteArrayList添加元素时,会复制⼀个新的数组,写操作在新数组......
  • redis学习笔记
    一、简单动态字符串SDS定义structsdsstr{//已保存的字符串长度intlen;//数组还剩余的空间intfree;//保存字符串的字节数组charbuf[];}获取字符串长度O(1)、......
  • vue-router的笔记
    路由:hash地址与组件之间的对应关系SPA:单页面应用程序前端路由的工作方式1、用户点击了页面上的路由链接2、导致了url地址栏的hash值变化3、前端路由监听到了hash地址......
  • vuex笔记
    Vuex在开发中,我们会的应用程序需要处理各种各样的数据,这些数据需要保存在我们应用程序中的某一个位置,对于这些数据的管理我们就称之为是状态管理src/store/index.js......
  • 学习笔记:重链剖分
    重链剖分前置芝士:线段树,dfs序,LCA概念一个非叶子节点,他的儿子中子树大小最大的就是重儿子,否则就是轻儿子对于一条边,如果连接的子节点是重儿子,那么这条边就是重边,否则......
  • 狂神说css学习笔记
    什么是CSSCascadingStyleSheet层叠级联样式表CSS:表现层(美化网页)如:字体,颜色,边距,高度,宽度,背景图片,网页定位,网页浮动等。CSS发展史CSS1.0CSS2.0DIV(块)+CSS,HTML和CSS......
  • 2023爬虫学习笔记 -- m3u8视频下载
    一、目标地址https://www.XXXX.com/二、获取mu38文件1、点击XHR,刷新页面,会看到这里有两个m3u8文件2、将m3u8地址复制到浏览器,会自动下载下来,index内容如下mixed内容如下3、......
  • 人月神话阅读笔记之一
    这段时间看了老师推荐的《人月神话》,这不是我第一次听闻这本书,当初的概论课上就有听老师说起过这本书,如今终于是第一次上手了。作者在书中的第一章——焦油坑,给我们讲述......