【总结】可并堆(左偏树)总结

简介

堆:可以查找集合最大值,支持插入元素,以及删除最大元素。

可并堆就在此基础上,支持快速合并两个集合的操作。


左偏树

首先,定义外节点为:其右儿子为空的节点。

定义距离为每个点到其子树中最近外接点的距离。

现在保证左儿子的距离值必须 不小于 右儿子的距离值。

这样,就能保证每个点往右走,走到叶子节点的步数不超过 l o g ( n ) log(n) log(n)步,其中 n n n表示这个节点的子树大小。

支持的操作:
1、合并

非常类似范浩强treap的合并方式。
比较简单,直接上代码

node *merge(node *x,node *y){
    if(x==NIL) return y;
    if(y==NIL) return x;	
    if(x->val > y->val)
        swap(x,y);
    x->ch[1]=merge(x->ch[1],y);
    if(x->ch[1]->dis > x->ch[0]->dis)
        swap(x->ch[0],x->ch[1]);
    x->dis=x->ch[1]->dis+1;
    return x;
}
2、删除根节点(或任意指定位置的节点)
void del(node *&x){
	x=merge(x->ch[0],x->ch[1]);
	//若是删除非根节点,则还需要再把x的子树和根合并
}

其他操作实在太简单,这里就不再赘述。

板题:洛谷P3377

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
struct node *NIL;
struct node{
    node *ch[2],*fa;
    int val,dis;
}Tree[MAXN];
void Newnode(node *x,int val){
    x->val=val;
    x->ch[0]=x->ch[1]=x->fa=NIL;
}
node *rt[MAXN];
int n,m;
void init(){
    NIL=Tree;
    NIL->ch[0]=NIL->ch[1]=NIL->fa=NIL;
    for(int i=1;i<=n;i++)
        rt[i]=Tree+i;
}
int fa[MAXN];
int get_fa(int x){
    if(fa[x]==0)
        return x;
    fa[x]=get_fa(fa[x]);
    return fa[x];	
}
node *merge(node *x,node *y){
    if(x==NIL)
        return y;
    if(y==NIL)
        return x;	
    if(x->val > y->val)
        swap(x,y);
    x->ch[1]=merge(x->ch[1],y);
    if(x->ch[1]->dis > x->ch[0]->dis)
        swap(x->ch[0],x->ch[1]);
    x->dis=x->ch[1]->dis+1;
    return x;
}
bool del[MAXN];
int main(){
    SF("%d%d",&n,&m);
    init();
    int val,tag,x,y;
    for(int i=1;i<=n;i++){
        SF("%d",&val);
        Newnode(Tree+i,val);
    }
    for(int i=1;i<=m;i++){
        SF("%d",&tag);
        if(tag==1){
            SF("%d%d",&x,&y);
            if(del[x]||del[y])
                continue;
            int fax=get_fa(x),fay=get_fa(y);
            if(fax==fay)
                continue;
            node *fx=rt[fax];
            node *fy=rt[fay];
            fa[fay]=fax;
            rt[fax]=merge(fx,fy);
        }
        else{
            SF("%d",&x);
            if(del[x]){
                PF("-1\n");
                continue;
            }
            int fax=get_fa(x);
            node *fx=rt[fax];
            del[fx-Tree]=1;
            PF("%d\n",fx->val);
            rt[fax]=merge(fx->ch[0],fx->ch[1]);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值