zoukankan      html  css  js  c++  java
  • 并不对劲的左偏树

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

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

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

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

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

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

    把它称为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
    */
    并不对劲的左偏树

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

  • 相关阅读:
    C#与Java的几点区别
    用VB读取记事本的内容,控制计算器的按钮(VB6)
    通过实例说明Java中的多态
    [导入]析构函数(内存泄漏,三法则)
    [导入]const限制符
    [导入]类的一些特殊限制成员
    [导入]基类的复制控制函数
    [导入]容器适配器
    [导入]派生类到基类转换的可访问性
    [导入](复制、默认)构造函数
  • 原文地址:https://www.cnblogs.com/xzyf/p/8378486.html
Copyright © 2011-2022 走看看