zoukankan      html  css  js  c++  java
  • 【暖*墟】#数据结构# 左偏树的学习与练习

    左偏树精髓部分:堆的合并

    int merge(int x,int y){ //*左偏树精髓*(大顶堆,返回堆顶元素)
    
        if(x==0||y==0) return (x+y); if(val[x]<val[y]) swap(x,y); //大顶堆
    
        ch[x][1]=merge(ch[x][1],y); fa[ch[x][1]]=x; //将一个堆的右子树和另一个堆比较
    
        if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]); //维护左偏性质
    
        if(ch[x][1]==0) dis[x]=0; else dis[x]=dis[ch[x][1]]+1; return x; 
    
    }

    左偏树模板题:洛谷 p3377

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<map>
    using namespace std;
    typedef long long ll;
    
    /*【p3377】左偏树 —— 可并堆
    一开始有N个小根堆,每个堆包含且仅包含一个数。
    操作1: 1 x y 将第x个数和第y个数所在的小根堆合并,
    操作2: 2 x 输出第x个数所在的堆最小数,并将其删除。*/
    
    //需要支持两个堆的合并,不能使用priority queue,需要手写左偏树。
    
    //感觉背代码比看文字更容易理解2333
    
    void reads(int &x){ //读入优化(正负整数)
        int fx=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')fx=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
        x*=fx; //正负号
    }
    
    const int N=100019;
    
    int ch[N][2],val[N],dis[N],fa[N],n,m;
    
    void swap(int &x,int &y){int t=x;x=y,y=t;}
    
    int find_fa(int x){ return fa[x]=(fa[x]==x)?x:find_fa(fa[x]); }
    
    int merge(int x,int y){ //*左偏树精髓*
        if(x==0||y==0) return (x+y);
        if(val[x]>val[y]||(val[x]==val[y]&&x>y)) swap(x,y);
        ch[x][1]=merge(ch[x][1],y); //↓↓维护左偏性质
        if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
        dis[x]=dis[ch[x][1]]+1,fa[ch[x][1]]=fa[ch[x][0]]=x; return x;
    }
    
    void pop(int x){ val[x]=-1,fa[ch[x][0]]=ch[x][0], //↓↓注意这里一定要更新fa[x]
        fa[ch[x][1]]=ch[x][1],fa[x]=merge(ch[x][0],ch[x][1]); }
    
    int main(){
        reads(n),reads(m); dis[0]=-1;
        for(int i=1;i<=n;i++) reads(val[i]),fa[i]=i;
        for(int i=1,op,x,y;i<=m;i++){ reads(op);
            if(op==1){ reads(x),reads(y);
                if(val[x]==-1||val[y]==-1) continue; //已经删除
                int fx=find_fa(x),fy=find_fa(y); merge(fx,fy); } 
            if(op==2){ reads(x); if(val[x]==-1){ puts("-1"); continue; }
                int y=find_fa(x); printf("%d
    ",val[y]); pop(y); } } 
    }

    左偏树练习题:洛谷 p1456

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<map>
    using namespace std;
    typedef long long ll;
    
    //【p1456】MK 必胜!(疯狂给小猴子打电话233)
    
    void reads(int &x){ //读入优化(正负整数)
        int fx=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')fx=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
        x*=fx; //正负号
    }
    
    const int N=100019;
    
    int ch[N][2],val[N],dis[N],fa[N],n,m;
    
    int find_fa(int x){ return fa[x]=(fa[x]==x)?x:find_fa(fa[x]); }
    
    int merge(int x,int y){ //*左偏树精髓*(大顶堆,返回堆顶元素)
        if(x==0||y==0) return (x+y); if(val[x]<val[y]) swap(x,y); //大顶堆
        ch[x][1]=merge(ch[x][1],y); fa[ch[x][1]]=x; //将一个堆的右子树和另一个堆比较
        if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]); //维护左偏性质
        if(ch[x][1]==0) dis[x]=0; else dis[x]=dis[ch[x][1]]+1; return x;
    }
    
    int pop(int x)
     { int l=ch[x][0],r=ch[x][1]; fa[l]=l,fa[r]=r,
       ch[x][0]=ch[x][1]=dis[x]=0; return merge(l,r); }
    
    int main(){
        while(scanf("%d",&n)!=EOF){
            for(int i=1;i<=n;i++) fa[i]=i,ch[i][0]=ch[i][1]=0,dis[i]=0;
            for(int i=1;i<=n;i++) reads(val[i]); reads(m);
            for(int i=1,x,y;i<=m;i++){ reads(x),reads(y);
                int fx=find_fa(x),fy=find_fa(y);
                if(fx==fy){ printf("-1
    "); continue; }
                val[fx]/=2,val[fy]/=2; //打斗以后权值减半
                //for(int i=1;i<=n;i++) cout<<val[i]<<" -- "; cout<<endl;
                int x_=pop(fx),y_=pop(fy); //删除根节点之后合并
                x_=merge(x_,fx),y_=merge(y_,fy); //堆和点合并
                x_=merge(x_,y_); printf("%d
    ",val[x_]); //两个堆合并
            }
        }
    }

                                              ——时间划过风的轨迹,那个少年,还在等你

  • 相关阅读:
    政府信息化建设重点——服务、多元化
    随便聊聊水面效果的2D实现(一)
    【Oracel 基础】小结
    漫话Unity(二)
    Codeforces Round #265 (Div. 2) C. No to Palindromes!
    C99中的restrict和C89的volatilekeyword
    开源 java CMS
    JavaScript--基于对象的脚本语言学习笔记(二)
    小试“以图搜图”
    计算几何 《模板》
  • 原文地址:https://www.cnblogs.com/FloraLOVERyuuji/p/10507309.html
Copyright © 2011-2022 走看看