左偏树(可并堆) [模板]

好一顿调试……

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

性质不多讲。

下文堆默认为小根堆

需维护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\n";
            else{
                cout<<v[find(x)]<<endl;
                _del(find(x));
            }
        }
    }
    return 0;
}

 

posted @ 2019-10-23 11:13  青珹  阅读(149)  评论(0编辑  收藏
Live2D