• [BZOJ 2654] tree


    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=2654

    [算法]

            给白色边都加上一个值,会使得最小生成树上的白边数量减少,不妨二分给白色边加上的值 ,  检验答案时用Kruskal求最小生成树即可

            时间复杂度 : O(NlogN)

    [代码]

           

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 100010
    #define MAXM 200010
    
    struct edge
    {
        int u , v , w , type;
    } e[MAXN];
    
    int tot , n , m , value , ans;
    int fa[MAXN];
    
    template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
    template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
    template <typename T> inline void read(T &x)
    {
       T f = 1; x = 0;
       char c = getchar();
       for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
       for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
       x *= f;
    }
    inline int get_root(int x)
    {
        if (fa[x] == x) return x;
        return fa[x] = get_root(fa[x]);
    }
    inline bool cmp(edge a , edge b)
    {
        return a.w == b.w ? a.type < b.type : a.w < b.w;
    }
    inline bool check(int mid)
    {
        int cnt = 0; 
        tot = 0;
        for (int i = 1; i <= n; i++) 
            fa[i] = i;
        for (int i = 1; i <= m; i++)
            if (!e[i].type) e[i].w += mid;    
        sort(e + 1 , e + m + 1 , cmp);
        for (int i = 1; i <= m; i++)
        {
            int su = get_root(e[i].u) , sv = get_root(e[i].v);
            if (su != sv)
            {
                fa[su] = sv;
                tot += e[i].w;
                if (!e[i].type) ++cnt;
            }
        }
        for (int i = 1; i <= m; i++) 
            if (!e[i].type) e[i].w -= mid;
        return cnt >= value;
    }
    
    int main()
    {
        
        read(n); read(m); read(value);
        for (int i = 1; i <= m; i++)
        {
            read(e[i].u);
            read(e[i].v);
            read(e[i].w);
            ++e[i].u; ++e[i].v;
            read(e[i].type);    
        }
        int l = -105 , r = 105 , ans = 0;
        while (l <= r)
        {
            int mid = (l + r) / 2;
            if (check(mid))
            {
                ans = tot - value * mid;
                l = mid + 1;    
            } else r = mid - 1;
        }
        printf("%d
    " , ans);
        
        return 0;
    }
  • 相关阅读:
    uboot编译配置过程
    APUE-数据库函数库
    值得推荐的C/C++框架和库 (真的很强大)
    ubuntu12.04图形界面与命令行界面切换
    ubuntu14.04 升级gcc的方法
    4. H5+css3
    3,css 内容
    2. 浏览器兼容性问题
    1,http协议
    页面添加水印
  • 原文地址:https://www.cnblogs.com/evenbao/p/9878730.html
Copyright © 2020-2023  润新知