zoukankan      html  css  js  c++  java
  • [Luogu3377]【模板】左偏树(可并堆)

    题面戳我
    题目描述
    如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:
    操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)
    操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)
    输入输出格式
    输入格式:
    第一行包含两个正整数N、M,分别表示一开始小根堆的个数和接下来操作的个数。
    第二行包含N个正整数,其中第i个正整数表示第i个小根堆初始时包含且仅包含的数。
    接下来M行每行2个或3个正整数,表示一条操作,格式如下:
    操作1 : 1 x y
    操作2 : 2 x
    输出格式:
    输出包含若干行整数,分别依次对应每一个操作2所得的结果。
    输入输出样例
    输入样例#1:

    5 5
    1 5 4 2 3
    1 1 5
    1 2 5
    2 2
    1 4 2
    2 2
    

    输出样例#1:

    1
    2
    

    说明
    当堆里有多个最小值时,优先删除原序列的靠前的,否则会影响后续操作1导致WA。
    时空限制:1000ms,128M
    数据规模:
    对于30%的数据:N<=10,M<=10
    对于70%的数据:N<=1000,M<=1000
    对于100%的数据:N<=100000,M<=100000

    sol

    左偏树模板题,考虑到要讲所以就把陈年代码翻出来写一写题解。
    我们考虑到左偏树的一个非常优秀的性质:树高的期望是(logn)
    所以判断是否在同一个堆中,只要暴力跳堆顶即可。
    (其实也是可以写个并查集的啦)
    其他就好说了。

    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAX=100005;
    int key[MAX],ls[MAX],rs[MAX],fa[MAX],dis[MAX],del[MAX],n,m;
    int gi()
    {
        int x=0,w=1;char ch=getchar();
        while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if (ch=='-') w=-1,ch=getchar();
        while (ch>='0'&&ch<='9')
        {
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }
        return x*w;
    }
    
    int Merge(int A,int B)
    {
        if (!A) return B;
        if (!B) return A;
        if (key[A]>key[B]||(key[A]==key[B]&&A>B)) swap(A,B);
        rs[A]=Merge(rs[A],B);
        fa[rs[A]]=A;
        if (dis[ls[A]]<dis[rs[A]]) swap(ls[A],rs[A]);
        dis[A]=dis[rs[A]]+1;
        return A;
    }
    void Delete(int A)
    {
        del[A]=1;
        fa[ls[A]]=fa[rs[A]]=0;
        Merge(ls[A],rs[A]);
    }
    int find(int x)
    {
        while (fa[x]) x=fa[x];
        return x;
    }
    int main()
    {
        n=gi();m=gi();
        for (int i=1;i<=n;i++) key[i]=gi();
        while (m--)
        {
            int opt=gi();
            if (opt==1)
            {
                int x=gi(),y=gi();
                int fx=find(x),fy=find(y);
                if (del[x]||del[y]||fx==fy) continue;
                Merge(fx,fy);
            }
            else
            {
                int x=gi();
                if (del[x]) printf("-1
    ");
                else
                {
                    int fx=find(x);
                    printf("%d
    ",key[fx]);
                    Delete(fx);
                }
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    java object bean 转map
    常用css
    mysql 生成max+1编号
    MySql避免重复插入记录方法(ignore,Replace,ON DUPLICATE KEY UPDATE)
    cookie记住账户密码
    session有效时间
    常用jstl
    高性能MySQL--innodb中事务的隔离级别与锁的关系
    mysql8.0.11的坑早知道
    git进阶--你可能不知道的很好用git功能
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8176328.html
Copyright © 2011-2022 走看看