• [BZOJ 2654] tree


    tree

    参考博客

    https://blog.csdn.net/y752742355/article/details/85468855

    https://www.cnblogs.com/cjyyb/p/9438101.html

    BZOJ 2654

    1

    题目大意

    给出一个无向图,每个边有一条边权以及一种颜色(0/1),问恰好有 (k) 条颜色为 (0) 的边的最小生成树,保证有解

    数据范围

    (Vle50000,Ele100000)

    时空限制

    30sec,512MB

    分析

    (F(x)) 为包含 (x)(0) 边的最小生成树大小,显然 (F(x)) 的斜率递增,而题目求最小值,符合这两个条件,那么就可以套用带权二分解决此题

    注意 (kruskal) 过程中要求出答案上界,将边权相同的 (0) 边排在前面

    Code

    #include <algorithm>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    inline char nc() {
    	static char buf[100000], *l = buf, *r = buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void read(T & x) {
    	x = 0; int f = 1, ch = nc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
    	x *= f;
    }
    const int maxn = 50000 + 5;
    const int maxm = 100000 + 5;
    const int maxv = 100 + 5;
    int n, m, k;
    int MST, mid;
    struct data {
    	int u, v, w, c;
    	bool operator < (const data & other) const {
    		int a = w + (c ? 0 : mid);
    		int b = other.w + (other.c ? 0 : mid);
    		if(a != b) return a < b;
    		return c < other.c;
    	}
    } e[maxm];
    struct union_set {
    	int fa[maxn];
    	void init() {
    		for(int i = 1; i <= n; ++i) fa[i] = i;
    	}
    	int find(int a) {
    		return a == fa[a] ? a : fa[a] = find(fa[a]);
    	}
    	bool merge(int a, int b) {
    		a = find(a), b = find(b);
    		if(a == b) return 0;
    		fa[a] = b; return 1;
    	}
    } us;
    bool judge() {
    	sort(e + 1, e + m + 1);
    	us.init();
    	int cnt = 0; MST = 0;
    	for(int i = 1; i <= m; ++i) {
    		int u = e[i].u, v = e[i].v;
    		if(us.merge(u, v)) {
    			MST += e[i].w + (e[i].c ? 0 : mid);
    			if(!e[i].c) cnt++;
    		}
    	}
    	return cnt >= k;
    }
    int solve() {
    	int l = -maxv, r = maxv, re;
    	while(l <= r) {
    		mid = (l + r) >> 1;
    		if(judge()) l = mid + 1, re = MST - k * mid;
    		else r = mid - 1;
    	}
    	return re;
    }
    int main() {
    //	freopen("testdata.in", "r", stdin);
    	read(n), read(m), read(k);
    	for(int i = 1; i <= m; ++i) {
    		read(e[i].u), read(e[i].v), read(e[i].w), read(e[i].c);
    		e[i].u++, e[i].v++;
    	}
    	printf("%d
    ", solve());
    	return 0;
    }
    
  • 相关阅读:
    MyBatis 笔记
    Python os模块、os.path模块常用方法
    vue-lazyload 的使用(vue图片懒加载)
    使用 vant 的 v-lazy 实现图片 vue 在移动端的懒加载
    代码注释规范-IDEA 配置 Java 类方法注释模板
    Java Web 笔记(杂)
    tortoisegit使用
    git结合github远程仓库使用
    .doc 2 .docx可用代码
    惊奇,MySQL还能正则匹配,简易例子
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/10252338.html
Copyright © 2020-2023  润新知