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. 福州大学W班-Beta冲刺评分

    作业链接 https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/1428 作业要求 1.博客具体要求 昨天的困 ...

  2. transient 与 volatile 笔记

    1. transient 词义:瞬间的,短暂的 首先说说"序列化",把一个对象的表示转化为字节流的过程称为串行化(也称为序列化,serialization),从字节流中把对象重建出 ...

  3. 遍历JSON

    第一种: each,不做详细说明,太常用了 第二种:我用来遍历单个组,实现前端界面绑定 for(var item in person){ alert("person中"+item+ ...

  4. Python内置函数(22)——list

    英文文档: class list([iterable]) Rather than being a function, list is actually a mutable sequence type, ...

  5. Mego开发文档 - 建模高级主题

    建模高级主题 在建模过程中我们还有许多其他情况,这里列出本框架中的有用特性来用于解决此类问题. 函数映射 我们可以将指定的CLR函数映射到数据库中的系统函数或自定义函数,该特性用于补充框架中未提供的数 ...

  6. Linux背景知识(1)RedHat和Centos

    Redhat有收费的商业版和免费的开源版,商业版的业内称之为RHEL(Red Hat Enterprise Linux)系列, 而这个CentOS(Community ENTerprise Opera ...

  7. angular2 学习笔记 ( angular cli & npm version manage npm 版本管理 )

    更新 : 2017-05-05 现在流行 Yarn ! 它是 facebook google 推出的东西. 算是补助 npm 做的不够好的地方. 源码依然是发布去 npm,只是下载接口换掉罢了哦. n ...

  8. Docker学习笔记 - Docker部署nginx网站

    一.制作 nginx 镜像 1.下载配置文件 mkdir /opt/nginx_docker && cd /opt/nginx_docker mkdir nginx && ...

  9. C++中explicit关键字

    explicit: 防止隐式转换使用. 隐式转换:不同类型的变量可以互相转换,如将一个整形数值赋值给一个类,ClassXX  lei = 4: C++中, 一个参数的构造函数(或者除了第一个参数外其余 ...

  10. 数据结构与算法 —— 链表linked list(03)

    继续关于linked list的算法题: 删除排序链表中的重复元素 给定一个排序链表,删除所有重复的元素使得每个元素只留下一个. 案例: 给定 1->1->2,返回 1->2 给定  ...