左偏树学习笔记

左偏树学习笔记

先给出定义吧

大概就是在堆的基础上要求维护一个另外的性质

定义 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

 

posted @   ZzTzZ  阅读(139)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示