• 模板


    这两个经常混在一起用的样子,封成同一个好了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int solve();
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in","r",stdin);
    #endif // Yinku
        solve();
    }
    
    int n,m;
    
    const int MAXN=100005;
    int tot,v[MAXN],l[MAXN],r[MAXN],d[MAXN],f[MAXN];
    
    //以siz为例代表并查集的信息,属于整棵左偏树
    int siz[MAXN];
    
    //这其实是一片左偏树-并查集森林,注意不要抄错Merge和_Merge
    class Leftist_Tree {
        int _Merge(int x,int y) {
            //将两棵左偏树合并,返回他们的新根
            //当其中一棵是空树,直接返回另一棵
            if(!x||!y)
                return x+y;
    
            //此处符号决定是最小堆还是最大堆
            //这里是小于号就是最大堆,是大于号就是小根堆
            //维持x不比y小,相等则把编号小的那个作为根,相等其实也可以灵活处理
            if(v[x]>v[y]||(v[x]==v[y]&&x>y)){
                swap(x,y);
            }
    
            r[x]=_Merge(r[x],y);
    
            //维持并查集的性质
            f[r[x]]=x;
            if(d[l[x]]<d[r[x]])
                swap(l[x],r[x]);
            d[x]=d[r[x]]+1;
            return x;
        }
        int Get_root(int x){
            //并查集
            //查找编号为x的节点所在的左偏树的根的序号,不需要可以删除
            int r=x;
            while(f[r]!=r)
                r=f[r];
            //路径压缩,直接指向他们的根
            int k;
            while(f[x]!=r){
                k=f[x];
                f[x]=r;
                x=k;
            }
            return r;
        }
    public:
        void Init(int n) {
            //使用v[]中的值初始化一片左偏树-并查集森林
            tot=n;
            for(int i=1; i<=n; i++) {
                l[i]=r[i]=d[i]=0;
                //建立并查集,连通块的性质由这里维护
                f[i]=i;
            }
        }
        int Top(int x){
            //返回x所在的左偏树的堆顶
            x=Get_root(x);
            return v[x];
        }
        int Pop(int x) {
            //将x所在的左偏树的堆顶弹出
            x=Get_root(x);
            //题目要求把v[x]删除,这里置为特殊值表示删除
            v[x]=-1;
            //将两个子树合并,相当于删除了堆顶
            //把一棵树的堆顶删除
            int rt=_Merge(l[x],r[x]);
            //在这里把树根的并查集性质导向新的树根rt,并把大家都指向新树根
            siz[x]=siz[l[x]]=siz[r[x]]=siz[x]-1;
            f[x]=f[l[x]]=f[r[x]]=f[rt]=rt;
            return rt;
        }
        bool Merge(int x,int y){
            x=Get_root(x);
            y=Get_root(y);
            if(x==y){
                //原本就是同一棵左偏树里面的
                return false;
            }
            else{
                //在这里更新并查集的信息
                siz[x]=siz[y]=(siz[x]+siz[y]);
                _Merge(x,y);
                return true;
            }
        }
    }lt;
    
    
    int solve() {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) {
            scanf("%d",&v[i]);
        }
    
        lt.Init(n);
    
        for(int i=1;i<=m;i++){
            int z,x,y;
            scanf("%d%d",&z,&x);
            if(z==1){
                scanf("%d",&y);
                if(v[x]==-1||v[y]==-1)
                    continue;
                lt.Merge(x,y);
            }
            else{
                if(v[x]==-1){
                    printf("-1
    ");
                }
                else{
                    printf("%d
    ",lt.Top(x));
                    lt.Pop(x);
                }
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    Git常用命令总结
    JavaScript单元测试框架JsUnit基本介绍和使用
    Android Home键监听
    ASP.NET Core on K8S深入学习(3-2)DaemonSet与Job
    你必须知道的Dockerfile
    你必须知道的Docker数据卷(Volume)
    《人人都是产品经理》读书笔记
    ASP.NET Core on K8S深入学习(3-1)Deployment
    ASP.NET Core on K8S深入学习(2)部署过程解析与Dashboard
    .NET Core on K8S学习与实践系列文章 (2020版)
  • 原文地址:https://www.cnblogs.com/Yinku/p/10961291.html
Copyright © 2020-2023  润新知