• 并不对劲的左偏树


    为了反驳隔壁很对劲的太刀流,并不对劲的片手流将与之针锋相对。

    很对劲的斜堆、左偏树简明教程->

    它们是可并堆的两种实现方式。

    (还是假装二叉堆只包括小根堆。)

    斜堆的缺点在于,每次合并的堆大小不同,无条件交换左右子树可能遇到某些坑孙子的数据,复杂度会变得玄学。

    左偏树是在斜堆上有所改进的。根据斜堆的代码,可以注意到合并的时间复杂度是第一个至多一个子树的点到根的距离。

    把它称为dis,那么当右子树的dis大于左子树的dis时才有必要交换。

    好像没那么玄学了呢。

    需要注意的是,至多一个子树的点的dis为0,而空节点的dis为-1。

    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define maxn 100010
    using namespace std;
    int read()
    {
        int f=1,x=0;char ch=getchar();
        while(isdigit(ch)==0 && ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void write(int x)
    {
        int ff=0;char ch[15];
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        while(x)ch[++ff]=(x%10)+'0',x/=10;
        if(ff==0)putchar('0');
        while(ff)putchar(ch[ff--]);
        putchar('
    ');
    }
    struct node
    {
        int key,ls,rs,dis;
    }xx[maxn];
    int fa[maxn],n,q;
    int x,y,l,r,tx,ty; 
    bool cmp(int _1,int _2)//Smaller.
    {
        return xx[_1].key==xx[_2].key?_1<_2:xx[_1].key<xx[_2].key;
    }
    int f(int x){return fa[x]<0?x:f(fa[x]);} 
    int merge(int A,int B) 
    {
        if(!A || !B)return A+B;
        if(!cmp(A,B))swap(A,B);
        xx[A].rs=merge(xx[A].rs,B);
        fa[xx[A].rs]=A;
        if(xx[xx[A].ls].dis<xx[xx[A].rs].dis)
            swap(xx[A].ls,xx[A].rs);
        xx[A].dis=xx[xx[A].rs].dis+1;
        return A;
    }
    void getit()
    {
        x=read(),y=read();
        if(xx[x].key<0 || xx[y].key<0)return;
        tx=f(x),ty=f(y);
        if(tx==ty)return;
        merge(tx,ty);
    }
    void delmin(int u)
    {
        l=xx[u].ls,r=xx[u].rs;
        xx[u].key=fa[l]=fa[r]=-1;
        merge(l,r);
    }
    void ask()
    {
    //    printfa();
        x=read();
        if(xx[x].key==-1){write(-1);return;}
        tx=f(x);
        write(xx[tx].key);
        delmin(tx);
    //    printfa();
    }
    void work()
    {
        n=read(),q=read();
        xx[0].dis=-1;
        memset(fa,-1,sizeof(fa));
        for(int i=1;i<=n;i++)
            xx[i].key=read();
        int f;
        while(q--)
        {
            f=read();
            if(f==1)
                getit();
            else 
                ask();
        }
    }
    int main()
    {
        work();
        return 0;
    }
    /*
    5 5
    1 5 4 2 3
    1 1 5
    1 2 5
    2 2
    1 4 2
    2 2
    */
    并不对劲的左偏树

      好像写得比简明教程还简明呢。

  • 相关阅读:
    [转]Modernizr的介绍和使用
    java动态代理使用详解
    ajax上传文件以及使用中常见问题处理
    cmd下查询端口占用以及根据进程id名称结束进程
    水平居中 垂直居中
    inline-block和float
    一起入门前端(三)
    一起入门前端(二)
    一起入门前端(一)
    WPF初学——自定义样式
  • 原文地址:https://www.cnblogs.com/xzyf/p/8378486.html
Copyright © 2020-2023  润新知