Description

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。

Input

第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

Output

一行表示所求生成树的边权和。

Sample Input

2 2 1
0 1 1 1
0 1 2 0

Sample Output

2

Hint

V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

题解

二分+$kruskal$

如果直接$kruskal$求最小生成树,是无法保证白边数量的,那么我们考虑如果改变白边的数量。我们可以把白边全部都加上一个权值,也就是我们二分的值,然后跑最小生成树,同时记录白边数量。当白边数量>=$need$时,$l=mid+1$,否则$r=mid−1$,更新答案就是这棵生成树的权值和减去所有白边的增量。

证明:
我们发现,如果我们给白边增加权值,做最小生成树,由于白边权值增大,导致不容易选白边。记$f(x)$为给白边增加$x$($x$可为负)权值,做最小生成树后,选白边的数量。可以发现,$f(x)$随$x$增大而减小,显然可以二分。
其次,我们发现,由于黑边的权值是不变的,与白边权值不相互影响。同样由于白边之间关系相对不变,必然选出的$need$条白边一定是符合题意的。

 #include<map>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
#define RE register
#define IL inline
using namespace std;
const int V=;
const int E=; int mid;
int v,e,need,ans,cnt,tmp;
struct tt
{
int u,v,c,col;
}edge[E+]; IL int Kruskal();
bool comp(const tt &a,const tt &b) {return a.c+(a.col^)*mid<b.c+(b.col^)*mid;} int set[V+];
IL int find(int r) {return set[r]!=- ? set[r]=find(set[r]):r;} int main()
{
scanf("%d%d%d",&v,&e,&need);
for (RE int i=;i<=e;i++) scanf("%d%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c,&edge[i].col);
int l=-,r=;
while (l<=r)
{
mid=(l+r)>>;
if (Kruskal()>=need) l=mid+,ans=tmp;
else r=mid-;
}
printf("%d\n",ans);
return ;
} IL int Kruskal()
{
tmp=cnt=;
int k=;
memset(set,-,sizeof(set));
sort(edge+,edge++e,comp);
for (RE int i=;i<=e;i++)
{
int q=find(edge[i].u);
int p=find(edge[i].v);
if (p!=q)
{
k+=edge[i].col^;
set[q]=p;
cnt++;
tmp+=edge[i].c;
if (cnt==v-) break;
}
}
return k;
}

BZOJ能过的解法

感谢Hzoi_Maple

由于$COGS$数据会有不满足恰好$need$条白边的情况

打个比方有这样的数据:加$0$时大于$need$,加$1$就小于$need$了。

这样应该在跑最小生成树的时候把所有的白边都加上加的那个权值,结果就是最小生成树的权值和减去$need*$加上的权值,多出来的那一部分完全可以当做黑边来看,因为数据是$100000$的,这样就可以了。(来自Hzoi_Maple

排序的时候,如果边权相同,要把白边放在前面。

要计算当前至多能取多少白边,当然要把白边放前面。由于保证有解,在$cnt>=need$且$cnt$取最小值的方案下,一定能有黑边把多余的白边代替掉。

 #include<map>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
#define RE register
#define IL inline
using namespace std;
const int V=;
const int E=; int mid;
int v,e,need,ans,cnt,tmp;
struct tt
{
int u,v,c,col,rc;
}edge[E+]; IL int Kruskal();
IL void change();
bool comp(const tt &a,const tt &b) {return a.rc==b.rc ? a.col<b.col:a.rc<b.rc;} int set[V+];
IL int find(int r) {return set[r]!=- ? set[r]=find(set[r]):r;} int main()
{
scanf("%d%d%d",&v,&e,&need);
for (RE int i=;i<=e;i++) scanf("%d%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c,&edge[i].col);
int l=-,r=;
while (l<=r)
{
mid=(l+r)>>;
if (Kruskal()>=need) l=mid+,ans=tmp-need*mid;
else r=mid-;
}
printf("%d\n",ans);
return ;
} IL void change()
{
for (RE int i=;i<=e;i++) edge[i].rc=edge[i].c+(edge[i].col^)*mid;
}
IL int Kruskal()
{
change();
tmp=cnt=;
int k=;
memset(set,-,sizeof(set));
sort(edge+,edge++e,comp);
for (RE int i=;i<=e;i++)
{
int q=find(edge[i].u);
int p=find(edge[i].v);
if (p!=q)
{
k+=edge[i].col^;
set[q]=p;
cnt++;
tmp+=edge[i].rc;
if (cnt==v-) break;
}
}
return k;
}

COGS能过的解法

[BZOJ 2654]tree(陈立杰)的更多相关文章

  1. [国家集训队2012]tree(陈立杰)

    [国家集训队2012]tree(陈立杰) 题目 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树.题目保证有解. INPUT 第一行V,E,need分别表示 ...

  2. BZOJ 2654: tree( 二分 + MST )

    我们给白色的边增加权值 , 则选到的白色边就会变多 , 因此可以二分一下. 不过这道题有点小坑... ------------------------------------------------- ...

  3. BZOJ 2654: tree Kruskal+二分答案

    2654: tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1863  Solved: 736[Submit][Status][Discuss ...

  4. bzoj 2654 tree - 二分法 - 最小生成树

    给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色边数. 接下来E行,每行 ...

  5. BZOJ 2654: tree

    Description \(n\) 个点, \(m\) 条边,边有权值和黑/白色,求含有 \(need\) 个白边的生成树. Sol 二分+Kruskal. 将每条白边都加上一个权值,然后跑最小生成树 ...

  6. bzoj 2654 tree 二分+kruskal

    tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 2739  Solved: 1126[Submit][Status][Discuss] Des ...

  7. BZOJ 2654 tree(二分答案+并查集)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2654 [题目大意] 给你一个无向带权连通图,每条边是黑色或白色. 让你求一棵最小权的恰 ...

  8. [国家集训队2012]tree(陈立杰) 题解(二分+最小生成树)

    tree 时间限制: 3 Sec  内存限制: 512 MB 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 输入 第一行V, ...

  9. hdu 4253 Two Famous Companies BZOJ 2654 tree

    [题意]:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值,问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 思路:我们发现,如果我们给 ...

随机推荐

  1. 听翁恺老师mooc笔记(9)--枚举

    枚举类型的定义 用符号而不是具体的数字来表示程序中的数字,这么表示的好处是可读性,当别人看你的程序,看到的是单词,很容易理解这些数字背后的含义,那么用什么符号来表示名字哪?需要const int常量的 ...

  2. 20162302 实验四《Android程序设计》实验报告

    实 验 报 告 课程:程序设计与数据结构 姓名:杨京典 班级:1623 学号:20162302 实验名称:Android程序设计 实验器材:装有Android Studio的联想拯救者80RQ 实验目 ...

  3. Archlinux安装和使用技巧

    一 准备工作 1  文件下载及启动盘制作 文件可以在https://mirrors.ustc.edu.cn/,这是个中科大的镜像网,选择如下: 下载完成后,就是制作一个启动盘,我使用的是Linux下强 ...

  4. 400多个开源项目以及43个优秀的Swift开源项目-Swift编程语言资料大合集

    Swift 基于C和Objective-C,是供iOS和OS X应用编程的全新语言,更加高效.现代.安全,可以提升应用性能,同时降低开发难度. Swift仍然处于beta测试的阶段,会在iOS 8发布 ...

  5. bzoj千题计划274:bzoj3779: 重组病毒

    http://www.lydsy.com/JudgeOnline/problem.php?id=3779 有一棵树,初始每个节点有不同的颜色 操作1:根节点到x的路径上的点 染上一种没有出现过的颜色 ...

  6. python之路--day8---day9--两日内容

    一.不使用函数的问题 1,代码的组织结构不清晰,可读性差 2,遇到重复的功能只能重复编写实现代码,代码冗余 3,功能需要扩展时,需要找出所有实现该功能的地方修改,无法统一管理且维护难度极大 二.函数是 ...

  7. Python内置函数(3)——max

    英文文档: max(iterable, *[, key, default]) max(arg1, arg2, *args[, key]) Return the largest item in an i ...

  8. kubernetes进阶(01)kubernetes的namespace

    一.Namespace概念 Namespace是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组. 常见的pods, services, replication co ...

  9. SpringCloud的EurekaClient : 客户端应用访问注册的微服务(无断路器场景)

    演示客户端应用如何访问注册在EurekaServer里的微服务 一.概念和定义 采用Ribbon或Feign方式访问注册到EurekaServer中的微服务.1.Ribbon实现了客户端负载均衡,2. ...

  10. maven入门(1-3)maven的生命周期

      maven的生命周期 maven的生命周期是抽象的,其实际行为都由插件来完成,引入maven 的 生命周期就是为了对所有的构建过程进行抽象和统一. 这种方式类似于模板方法,模板方法模式在父类中定义 ...