左偏树学习笔记
左偏树学习笔记
先给出定义吧
大概就是在堆的基础上要求维护一个另外的性质
定义 dis[i]为i到自己子树中所有不满足 有两个儿子 这个条件的节点中 最短 距离
所以它大概长这个样子
要求维护堆的结构 使得对于一个节点 U 满足 dis[ls[U]] ≥ dis[rs[U]
可以看出这其实是一个极其不平衡的一个堆(树)
所以我们要它干什么呢?赶紧写splay转啊
其实主要是用于合并两棵树用的
先考虑它有啥性质吧
根的深度不超过 log(n)
节点的权值小于等于左右儿子的权值
dis[u] = dis[rs[u]]+1; (因为一定是左右儿子中最小的+1
左偏树的距离为一个定值,则为完全二叉树
(还挺显然的
使用以上这些性质就可以做到:
合并!!!
是的,不需要动态开点splay,您可以在 O(logn) 复杂度以内实现两个左偏树的合并
具体实现如下:
1. 如果x的根节点val大于y根节点的val,那么swap(x,y),目的是保证把大的合并到小的上。
2. 将y的根和x的右子树判断是否满足1的规则,递归合并,缩小规模,直到一个叶子节点,那么直接修改 tree[x].rc=y,这样完成合并。
3. 如果在合并过程中出现了 距离不满足左大于右 的情况了 那么就直接
4. 合并完之后,dis[u]=dis[rs]+1
具体实现:
struct mergeheap { int val[maxn],ff[maxn],ls[maxn],rs[maxn],dis[maxn]; bool vis[maxn]; void init(int n) {inc(i,1,n) rt[i]=i;dis[0]=-1;} int find(int x) {return (ff[x]==x) ? x : ff[x]=find(ff[x]);} int link(int x,int y) { if(!x||!y) return x|y; if((val[x]>val[y]) || (val[x]==val[y]&&x>y)) swap(x,y); rs[x]=link(rs[x],y); if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]); dis[x]=dis[rs[x]]+1; return ff[ls[x]]=ff[rs[x]]=x; } void merge(int x,int y) { if(vis[x] || vis[y]) return; int x=find(x) , y=find(y); if(x!=y) ff[x]=ff[y]=link(x,y); } int top(int x) { if(vis[x]) return -1; x=find(x); retutrn val[x]; } void pop(int x) { if(vis[x]) return; x=find(x); vis[x]=1; ff[x]=ff[ls[x]]=ff[rs[x]]=link(ls[x],rs[x]); } }h;
就先这样吧(x
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了