左偏树学习笔记
左偏树学习笔记
先给出定义吧
大概就是在堆的基础上要求维护一个另外的性质
定义 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

浙公网安备 33010602011771号