• 洛谷P4234 最小差值生成树(lct动态维护最小生成树)


    题目描述

    给定一个标号为从 11 到 nn 的、有 mm 条边的无向图,求边权最大值与最小值的差值最小的生成树。

    输入输出格式

    输入格式:

     

    第一行两个数 n, mn,m ,表示图的点和边的数量。

    第二行起 mm 行,每行形如 u_i, v_i, w_iui,vi,wi ,代表 u_iui 到 v_ivi 间有一条长为 w_iwi 的无向边。

     

    输出格式:

     

    输出一行一个整数,代表你的答案。

    数据保证存在至少一棵生成树。

     

    输入输出样例

    输入样例#1: 复制
    4 6 
    1 2 10 
    1 3 100 
    1 4 90 
    2 3 20 
    2 4 80 
    3 4 40 
    输出样例#1: 复制
    20

    说明

    对于 30% 的数据,满足 1 leq n leq 100, 1 leq m leq 10001n100,1m1000

    对于 97% 的数据,满足 1 leq n leq 500, 1 leq m leq 1000001n500,1m100000

    对于 100% 的数据,满足 1 leq n leq 50000, 1 leq m leq 200000, 1 leq w_i leq 100001n50000,1m200000,1wi10000

    题解:有自环是真的毒瘤……反正思路是从大到小枚举每条边作为最小边构成的生成树,然后显然他要加进去就要把原环上最大值扔掉,这样子动态加边删边,就可以搞出答案了

    还有个问题是怎么维护最小生成树里的最大值,因为权值很小,所以可以考虑搞一个cnt,一开始pos等于最大边w,接着如果最大边被删掉了,就暴力往下跳pos,直到cnt[pos]>0为止,这样子均摊一下复杂度是O(1)的

    代码如下:

    #include<map>
    #include<set>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 300010
    #define M 350010
    #define lson ch[x][0]
    #define rson ch[x][1]
    using namespace std;
    
    int cnt[10010],max1,n,m,ans=0x3f3f3f3f;
    
    struct node
    {
        int from,to,w;
    } e[N];
    
    int cmp(node a,node b)
    {
        return a.w<b.w;
    }
    
    //lct begin
    
    int tag[M],f[M],ch[M][2],sum[M];
    
    int not_root(int now)
    {
        int x=f[now];
        return lson==now||rson==now;
    }
    
    int push_up(int x)
    {
        sum[x]=x;
        if(e[sum[lson]].w>e[sum[x]].w)
        {
            sum[x]=sum[lson];
        }
        if(e[sum[rson]].w>e[sum[x]].w)
        {
            sum[x]=sum[rson];
        }
    }
    
    int rev(int x)
    {
        swap(lson,rson);
        tag[x]^=1;
    }
    
    int push_down(int x)
    {
        if(tag[x])
        {
            rev(lson);
            rev(rson);
            tag[x]^=1;
        }
    }
    
    int rotate(int x)
    {
        int y=f[x],z=f[y],kd=ch[y][1]==x,xs=ch[x][!kd];
        if(not_root(y))
        {
            ch[z][ch[z][1]==y]=x;
        }
        ch[x][!kd]=y;
        ch[y][kd]=xs;
        if(xs) f[xs]=y;
        f[y]=x;
        f[x]=z;
        push_up(y);
    }
    
    int push_all(int x)
    {
        if(not_root(x))
        {
            push_all(f[x]);
        }
        push_down(x);
    }
    
    int splay(int x)
    {
        int y,z;
        push_all(x);
        while(not_root(x))
        {
            y=f[x],z=f[y];
            if(not_root(y))
            {
                (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
            }
            rotate(x);
        }
        push_up(x);
    }
    
    int access(int x)
    {
        for(int y=0; x; y=x,x=f[x])
        {
            splay(x);
            rson=y;
            push_up(x);
        }
    }
    
    int make_root(int x)
    {
        access(x);
        splay(x);
        rev(x);
    }
    
    int split(int x,int y)
    {
        make_root(x);
        access(y);
        splay(y);
    }
    
    int find_root(int x)
    {
        access(x);
        splay(x);
        while(lson)
        {
            push_down(x);
            x=lson;
        }
        return x;
    }
    
    int link(int x,int y)
    {
        make_root(x);
        if(find_root(y)==x) return 0;
        f[x]=y;
        return 1;
    }
    
    int cut(int x,int y)
    {
        make_root(x);
        if(find_root(y)!=x||f[x]!=y||rson) return 0;
        f[x]=ch[y][0]=0;
        push_up(y);
        return 1;
    }
    
    int print(int x)
    {
        if(lson) print(lson);
        printf("%d ",x);
        if(rson) print(rson);
    }
    
    //lct end
    
    //dsu begin
    
    int fa[M];
    
    int init()
    {
        for(int i=1; i<M; i++)
        {
            fa[i]=i;
        }
    }
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    
    int unity(int x,int y)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx==fy) return 0;
        fa[fx]=fy;
        return 1;
    }
    
    //dsu end
    
    int main()
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w);
        }
        sort(e+1,e+m+1,cmp);
        int tot=0;
        for(int i=m; i>=1; i--)
        {
            if(e[i].from==e[i].to) continue;
            if(unity(e[i].from,e[i].to))
            {
                tot++;
                link(e[i].from+m,i);
                link(e[i].to+m,i);
                cnt[e[i].w]++;
                max1=max(max1,e[i].w);
                if(tot==n-1) ans=max1-e[i].w;
            }
            else
            {
                split(e[i].from+m,e[i].to+m);
                int gg=sum[e[i].to+m];
                cut(e[gg].to+m,gg);
                cut(e[gg].from+m,gg);
                cnt[e[gg].w]--;
                cnt[e[i].w]++;
                while(!cnt[max1])
                {
                    max1--;
                }
                if(tot==n-1) ans=min(ans,max1-e[i].w);
                link(e[i].to+m,i);
                link(e[i].from+m,i);
            }
        }
        printf("%d
    ",ans);
    }
  • 相关阅读:
    汇编学习笔记(3)[bx]和loop
    C++面试题-概念篇(一)
    命名空间的冷思考
    背包以及装备模块封装的思考
    虚函数,纯虚函数以及虚继承
    组件化开发在游戏开发当中的思考和汇总
    Netty和MINA之间的比较思考
    学习C++与Java之间的区别
    C++服务器年前总结
    C++Builder如何将当前时间与字符串相互转换
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9485774.html
Copyright © 2020-2023  润新知