zoukankan      html  css  js  c++  java
  • 模板:左偏树

    如果你知道priority_queue的话,那自然就知道左偏树的目的了。

    左偏树的目的和优先队列一致,就是求出当前所在堆中的最大(小)值。

    但是我们作为高贵的C++选手,我们为什么还要学习左偏树呢。

    当然是因为priority_queue太!慢!了!

    ————————————————————————————————————

    概念引入:

    对于左偏树,我们引入两个概念:

    外节点:如果该节点的左子树或右子树为空,那么该节点为外节点。

    距离(dis):该节点到达最近的外节点经过的边的个数。

    我们同时将优先队列的定义照搬过来:

    键值(val):节点的权值。

    同时将优先队列的性质照搬过来:

    性质1:节点的键值小于或等于它的左右子节点的键值。

    对于左偏树,赋予它一个性质:

    性质2:节点的左子节点的距离不小于右子节点的距离。

    同时可以推出:

    性质3:节点的距离等于它的右子节点的距离加1。(显然)

    为了满足性质3,我们规定空节点的dis为-1。

    此外还有很多性质,不过都是跟推左偏树复杂度相关的性质,有兴趣可以百度。

    ——————————————————————

    复杂度:

    这里直接给出左偏树的复杂度:

    合并:O(logN1+logN2)(N1和N2分别为待合并左偏树的节点个数)

    插入:O(logn)

    删除最小节点:O(logn)

    建树:O(n)

    删除已知编号节点:O(logn)

    ————————————————————

    基本操作:

    以建立大根堆为例,现将前三个操作说明。

    合并:

      按照左偏树的定义合并即可。

      设要合并的两个堆的根节点为x,y。

      如果其中一个堆为空堆,则不需合并。

      否则比较它们的val,设x为val较小的堆根节点。

      则x显然是新堆(子堆)的根节点,但是y在哪里我们并不知道。

      为了满足左偏树的性质(不提供证明),我们将x的右子堆和y堆合并,最后按照它们的dis交换一下左右儿子即可。

    插入:

      将插入元素看成堆的话,与合并相同。

    删除最小节点:

      将根节点删除后,其左右子堆合并即可。

    ————————————————————————————————

    学到这里代码实现不是很难,这里提供板子题目:

    洛谷P3377:[模板]左偏树(可并堆):https://www.luogu.org/problemnew/show/3377

    代码如下:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cctype>
    #include<queue>
    using namespace std;
    const int N=1e5+3;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int fa[N];
    struct tree{
        int l,r;
        int dis,val;
    }tr[N];
    int merge(int x,int y){//两个堆的根,返回新堆的根
        if(x==0||y==0)return x+y;//其中一个是空堆
        if(tr[x].val>tr[y].val||(tr[x].val==tr[y].val&&x>y))
        swap(x,y);//让x的价值比y的价值小,这样x就在y上面
        tr[x].r=merge(tr[x].r,y);//合并x右树和y
        fa[tr[x].r]=x;
        if(tr[tr[x].l].dis<tr[tr[x].r].dis)
        swap(tr[x].l,tr[x].r);//让右儿子更接近外节点
        tr[x].dis=tr[tr[x].r].dis+1;//根据右儿子dis更新节点dis
        return x;
    }
    int get(int x){
        while(fa[x])x=fa[x];
        return x;
    }
    void del(int x){
        tr[x].val=-1;
        fa[tr[x].l]=fa[tr[x].r]=0;
        merge(tr[x].l,tr[x].r);
        return;
    }
    int main(){
        int n=read();
        int m=read();
        for(int i=1;i<=n;i++)tr[i].val=read();
        for(int i=1;i<=m;i++){
        int c=read();
        if(c==1){
            int x=read();
            int y=read();
            if(tr[x].val==-1||tr[y].val==-1||x==y)continue;
            int nx=get(x);
            int ny=get(y);
            merge(nx,ny);
        }else{
            int x=read();
            if(tr[x].val==-1){
            puts("-1");
            }else{
            int y=get(x);
            printf("%d
    ",tr[y].val);
            del(y);
            }
        }
        }
        return 0;
    }

     例题

    BZOJ2809:[Apio2012]dispatching:http://www.cnblogs.com/luyouqi233/p/7999445.html

    POJ3666:Making the Grade:http://www.cnblogs.com/luyouqi233/p/8005148.html

  • 相关阅读:
    autocomplete自动完成搜索提示仿google提示效果
    实现子元素相对于父元素左右居中
    javascript 事件知识集锦
    让 IE9 以下的浏览器支持 Media Queries
    「2013124」Cadence ic5141 installation on CentOS 5.5 x86_64 (limited to personal use)
    「2013420」SciPy, Numerical Python, matplotlib, Enthought Canopy Express
    「2013324」ClipSync, Youdao Note, GNote
    「2013124」XDMCP Configuration for Remote Access to Linux Desktop
    「2013115」Pomodoro, Convert Multiple CD ISO to One DVD ISO HowTo.
    「2013123」CentOS 5.5 x86_64 Installation and Configuration (for Univ. Labs)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/7994462.html
Copyright © 2011-2022 走看看