zoukankan      html  css  js  c++  java
  • 左偏树(可并堆) [模板]

    好一顿调试……

    左偏树,又叫可并堆,顾名思义,它是支持合并的堆。

    性质不多讲。

    下文堆默认为小根堆

    需维护v[i]  //i节点的值

               ls[i] //i的左儿子

               rs[i] //i的右儿子

               fa[i] //i所在堆的根

               dis[i] //以i为根节点的树的距离(这里不多讲距离有什么用)

               vis[i] //i是否被删除了 (这个不是必须维护的,可以有其他替代手段,这里给出一个例子:将v[i]=-1,代替vis数组的作用)

    可支持的操作:

    1.合并两个堆

    我们设两个堆的根节点为 x,y

    则合并操作为 merger(x,y)

    若 x<y 则合成后的新堆顶为 x ,为了方便,若 x>y 则交换 x,y,变为 x<y

    这样根节点确定后,我们可以继续合并 x的右子树和y ,将合并出来的东西替换掉原来 x 的右子树

    这样进行递推合并即可

    每次合并需要维护的内容 :

    dis[x],fa[ls[x]],fa[rs[x]]

    2.删除堆顶

    可以将左右两个儿子合并成新的堆

    需要维护的东西:

    fa[ls[x]]=ls[x]

    fa[rs[x]]=rs[x]

    vis[x]=1

    fa[x]=merge(ls[x],rs[x])//注意:根节点的祖先连到新的堆的根,这样才能保证并查集不断层

    代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define MAXN 100011
    using namespace std;
    int n,m;
    int ls[MAXN],rs[MAXN],dis[MAXN],v[MAXN],fa[MAXN],vis[MAXN];
    
    inline int read(){
        int x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9')
            ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x;
    }
    
    int merger(int x,int y){
        if(!x||!y)
            return x|y;
        if(v[x]>v[y]||(v[x]==v[y]&&x>y))
            swap(x,y);
        rs[x]=merger(rs[x],y);
        fa[rs[x]]=x;
        if(dis[ls[x]]<dis[rs[x]])
            swap(ls[x],rs[x]);
        dis[x]=dis[rs[x]]+1;
        return x;
    }
    int find(int x){
        if(fa[x]==x)
            return x;
        return fa[x]=find(fa[x]);
    }
    void _del(int x){
        fa[ls[x]]=ls[x];
        fa[rs[x]]=rs[x];
        fa[x]=merger(ls[x],rs[x]);
        vis[x]=1;
        return ;
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++){
            v[i]=read();
            fa[i]=i;
        }
        for(int i=1;i<=m;i++){
            int k=read(),x=read();
            if(k==1){
                int y=read();
                if(vis[x]||vis[y])
                    continue ;
                merger(find(x),find(y));
            }
            else{
                if(vis[x])
                    cout<<"-1
    ";
                else{
                    cout<<v[find(x)]<<endl;
                    _del(find(x));
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    Hdu3022 Sum of Digits
    bzoj3864 Hero meet devil
    bzoj2448 挖油
    poj3783 Balls
    bzoj3802 Vocabulary
    Hdu5181 numbers
    Hdu5693 D Game
    图形填充之边标志算法
    图形填充之栅栏填充算法
    图形填充之种子填充算法
  • 原文地址:https://www.cnblogs.com/qiuchengrui/p/11725186.html
Copyright © 2011-2022 走看看