• luogu_P3377 左偏树(可并堆)


    传送门:https://www.luogu.org/problem/P3377

    左偏树:左偏!也就是下面这种左边大,右边小的树

    可并堆:可以合并的堆(堆:维护最值的数据结构)

    核心(细节): 

      先来代码

    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(val[x]>val[y] || (val[x]==val[y]&&x>y)) swap(x,y);
        rs[x]=merge(rs[x],y);
        rt[rs[x]]=rt[ls[x]]=x;
        if(h[rs[x]]>h[ls[x]]) swap(rs[x],ls[x]);
        h[x]=h[rs[x]]+1;
        return x;
    }

    在合并时,往右子树走,当发现右边的值不合法时,则另另一个堆的值来swap

      以最大值为例: 当发现x<y时,让堆的右儿子为y,把原来那颗子树扯出来,继续合并

      每次合并完之后更新高度(一个节点的高度=它的右儿子高度+1)

      

    还有一点就是在删除的时候,先找到堆顶,删除,然后merge(rs[x],ls[x])

    记得令 root[x]=merge(rs[x],ls[x]) 因为有路径压缩,所以有很多节点的top还是x

    #include<cstdio>
    #include<algorithm>
    #define R register
    using namespace std;
    int n,m,val[100100],rt[100100],ls[100100],rs[100100],h[100100];
    int find(int x){
        return rt[x]==x? x:rt[x]=find(rt[x]);
    }
    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(val[x]>val[y] || (val[x]==val[y]&&x>y)) swap(x,y);
        rs[x]=merge(rs[x],y);
        rt[rs[x]]=rt[ls[x]]=x;
        if(h[rs[x]]>h[ls[x]]) swap(rs[x],ls[x]);
        h[x]=h[rs[x]]+1;
        return x;
    }
    void pop(int x){
        val[x]=-1;rt[rs[x]]=rs[x];rt[ls[x]]=ls[x];
        rt[x]=rt[rs[x]]=rt[ls[x]]=merge(rs[x],ls[x]);
        return;
    }
    int main (){
        scanf("%d%d",&n,&m);
        for(R int i=1;i<=n;i++){
            scanf("%d",&val[i]);rt[i]=i;
        }
        h[0]=-1;
        for(R int c,x,y,i=1;i<=m;i++){
            scanf("%d",&c);
            if(c==1){
                scanf("%d%d",&x,&y);
                if(val[x]==-1|| val[y]==-1) continue;
                x=find(x);y=find(y);
                if(x==y) continue;
                rt[x]=rt[y]=merge(x,y);        
            }
            else{
                scanf("%d",&x);
                if(val[x]==-1) printf("-1
    ");
                else {
                    y=find(x);
                    printf("%d
    ",val[y]);
                    pop(y);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    SQLServer中查询的数字列前面补0返回指定长度的字符串
    Http Module 介绍
    SQLite中使用时的数据类型注意
    SQLite中的PRAGMA语句攻略
    Sqlite中使用rowid来表示行号,用于分页。
    Sqlite基础及其与SQLServer语法差异
    SQLite中的日期基础
    Asp.net页面无刷新请求实现
    CSS3实现的渐变按钮,在IE7、IE6下的滤镜使用。
    如何给网站页面添加图标?
  • 原文地址:https://www.cnblogs.com/coclhy/p/11637974.html
Copyright © 2020-2023  润新知