zoukankan      html  css  js  c++  java
  • 洛谷 P5633 最小度限制生成树 wqs二分

    wqs二分常用来解决这样的问题:在某个限定条件 (k) 下,求最大/最小值。

    wqs二分就是先不管条件 (k) ,看这时取到最值的情况下条件满足的怎么样,然后对和这个条件有关,能影响到最值的部分二分加权,再看满足的怎么样。

    这道题的话我们先二分一个权值 (val) ,让和 (s) 相连的边都加上 (val) ,看最后选了多少条和 (s) 相连的边,再根据这个调整 (val).

    套上一个克鲁斯卡尔生成树就完了。注意这题判无解的情况。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n, m, s, k, x, y, z, tot0, tot1, tmp, l, r, mid, ans, cnt;
    long long res;
    const int N = 50005, M = 500005, inf = 1e9;
    int fa[N];
    struct bian
    {
    	int x, y, z, is;
    	friend bool operator <(const bian &a, const bian &b) {return a.z < b.z;}
    } b[2][M], e[M];
    int find(int x) {return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);}
    void he(int x, int y) {fa[find(x)] = fa[find(y)];}
    int check(int mid)
    {
    	for (int i = 1; i <= tot1; ++i)b[1][i].z += mid;
    	int i, j, o; i = j = o = 0;
    	while (i < tot0 && j < tot1)
    	{
    		if (b[0][i + 1] < b[1][j + 1])e[++o] = b[0][++i];
    		else e[++o] = b[1][++j];
    	}
    	while (i < tot0)e[++o] = b[0][++i];
    	while (j < tot1)e[++o] = b[1][++j];
    	for (int i = 1; i <= tot1; ++i)b[1][i].z -= mid;
    
    	res = cnt = 0;
    	for (int i = 1; i <= n; ++i)fa[i] = i;
    	for (int i = 1, js = 0; i <= m; ++i)
    	{
    		x = e[i].x; y = e[i].y;
    		if (find(x) == find(y))continue;
    		he(x, y);
    		if (e[i].is)++cnt;
    		res += e[i].z;
    		if ((++js) == n - 1)break;
    	}
    	return cnt >= k;
    }
    int main()
    {
    	cin >> n >> m >> s >> k;
    	for (int i = 1; i <= m; ++i)
    	{
    		scanf("%d%d%d", &x, &y, &z);
    		if (x == s || y == s)b[1][++tot1] = (bian) {x, y, z, 1};
    		else b[0][++tot0] = (bian) {x, y, z, 0};
    	}
    	if (tot1 < k)return puts("Impossible") == 2333;
    	for (int i = 1; i <= n; ++i)fa[i] = i;
    	tmp = n;
    	for (int i = 1; i <= tot0; ++i)
    		if (find(b[0][i].x) != find(b[0][i].y))he(b[0][i].x, b[0][i].y), --tmp;
    	for (int i = 1; i <= tot1; ++i)
    		if (find(b[1][i].x) != find(b[1][i].y))he(b[1][i].x, b[1][i].y), --tmp;
    	if (tmp > 1)return puts("Impossible") == 2333;
    	sort(b[0] + 1, b[0] + 1 + tot0); sort(b[1] + 1, b[1] + 1 + tot1);
    	l = -inf; r = inf; ans = l;
    	if (!check(l))return puts("Impossible") == 2333;
    	while (l <= r)
    	{
    		mid = (l + r) >> 1;
    		if (check(mid))ans = mid, l = mid + 1;
    		else r = mid - 1;
    	}
    	check(ans);
    	if (cnt != k)puts("Impossible");
    	else cout << res - (long long)k*ans;
    	return 0;
    }
    
  • 相关阅读:
    Java 标记接口
    数据结构 红黑树
    项目实践总结 存储短信验证码
    Java Web 浏览器关闭后Session就会被销毁吗?
    Java Web 禁用Cookie对Session的影响
    Java 接口 新特性(Java8)
    项目实践总结 修改个人资料时避免不必要的修改
    Java 多线程 sleep()方法与yield()方法的区别
    续XX后对一些想法的认同(两则)
    POLYCOM Group 310 远程视频会议系统项目 高清视频会议终端
  • 原文地址:https://www.cnblogs.com/wljss/p/12601368.html
Copyright © 2011-2022 走看看