左偏树模板

看大佬们的博客吧QwQ

https://www.cnblogs.com/yyf0309/p/LeftistTree.html

https://www.luogu.org/blog/cytus/ke-bing-dui-zhi-zuo-pian-shu

我就放一下代码就好了

以下删除皆为顶点

删除特定节点什么的以后会补充的

嗯……

维护一颗左偏的二叉树,以及并查集,最主要的是可并

#include<bits/stdc++.h>
#define re return
#define ll long long 
#define inc(i,l,r) for(register int i=l;i<=r;++i)

const int maxn=100005;
using namespace std;
char buf[1<<21],*p1,*p2;
inline int gc(){re p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=gc())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=gc())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x; 
}

int n,m,fa[maxn],val[maxn],ls[maxn],rs[maxn],dist[maxn];

inline int find(int x)
{
    re x==fa[x]?x:fa[x]=find(fa[x]);
}
//合并x,y; 
inline int merge(int x,int y)
{
    if(!x||!y)re x+y;
    //将现存子树根节点,接在上一个节点的右子树 
    if(val[x]>val[y]||(val[x]==val[y]&&x>=y))
        x^=y^=x^=y;
    //维护小根堆性质,根节点是最小的 
    rs[x]=merge(rs[x],y);
    //递归合并 
    fa[rs[x]]=x;
    //维护新的右子树fa值 
    if(dist[ls[x]]<dist[rs[x]])swap(ls[x],rs[x]);
    //维护左偏 
    dist[x]=dist[rs[x]]+1;
    
    re x;
}
int main()
{
    rd(n),rd(m);
    inc(i,1,n)
    {
        fa[i]=i;
        rd(val[i]);
    }    
    
    dist[0]=-1;
    //如果右子树为0,则根节点高度为0 
    int opt,x,y;
    inc(i,1,m)
    {
        rd(opt);
        if(opt==1)
        {
            rd(x),rd(y);
            //如果没有这个数,或者已经同在一个堆里,则跳过 
            if(val[x]==-1||val[y]==-1)continue; 
            x=find(x);y=find(y);
            if(x==y)continue;
            merge(x,y);
        }
        else 
        {
            rd(x);
            if(val[x]==-1)
            printf("-1\n");
            else
            {
                x=find(x);
                printf("%d\n",val[x]);
                val[x]=-1;
                int v=merge(ls[x],rs[x]);
                fa[v]=fa[x]=v;//防止find压缩路径出锅 
            } 
            
        }
    }

    re 0; 
}

 

posted @ 2019-08-14 20:26  凉如水  阅读(113)  评论(0编辑  收藏  举报