BZOJ2654 tree

Description

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

题目保证有解。

Input

第一行V,E,need分别表示点数,边数和需要的白色边数。

接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

Output

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

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

Sample Input

2 2 1
0 1 1 1
0 1 2 0

Sample Output

2

HINT

原数据出错,现已更新 by liutian,但未重测---2016.6.24

正解:二分答案+最小生成树

解题报告:

  今天LCF的分治题出了这道农boy题,完全不知道跟分治有什么关系。。。

  题解太神,想通这么搞的目的之后就很简单了。

  首先如果直接做,显然用的白边不一定是要求的值,如果边数多了,那么我们考虑如果所有的白边都增加一个值,显然白边数不会增加,应该会减少。这样就可以使我们确定答案选取了哪些白边。边数少了的话,也是一个道理。所以我们考虑二分答案,增加减少的边权必须在边权范围内(多了没意义)。

  注意一下细节,相等情况下,先选白边,可以证明更优。我是蒟蒻,我不会证。

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 100011;
21 const int MAXM = 400011;
22 int n,m,allow;
23 int first[MAXN];
24 int father[MAXN];
25 int ecnt,cnt;
26 LL tot;
27 LL ans;
28
29 struct edge{
30     int u,v,w;
31     int flag;
32 }e[MAXM];
33
34 inline int getint()
35 {
36        int w=0,q=0;
37        char c=getchar();
38        while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
39        if (c==‘-‘)  q=1, c=getchar();
40        while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
41        return q ? -w : w;
42 }
43
44 inline int find(int x){
45     if(father[x]!=x) father[x]=find(father[x]);
46     return father[x];
47 }
48
49 inline bool cmp(edge q,edge qq){ if(q.w==qq.w) return q.flag<qq.flag;  return q.w<qq.w; }
50
51 inline bool check(int x){
52     for(int i=1;i<=n;i++) father[i]=i;
53     for(int i=1;i<=m;i++) if(!e[i].flag) e[i].w+=x;
54     sort(e+1,e+m+1,cmp);
55     int r1,r2; cnt=0; tot=0;
56     for(int i=1;i<=m;i++) {
57     r1=find(e[i].u); r2=find(e[i].v);
58     if(r1!=r2) {
59         father[r2]=r1;
60         if(!e[i].flag) cnt++;
61         tot+=e[i].w;
62     }
63     }
64     for(int i=1;i<=m;i++) if(!e[i].flag) e[i].w-=x;
65     if(cnt>=allow) return true;
66     return false;
67 }
68
69 inline void work(){
70     n=getint(); m=getint(); allow=getint();
71     for(int i=1;i<=m;i++) {
72     e[i].u=getint(); e[i].v=getint(); e[i].w=getint(); e[i].flag=getint();
73     }
74     int l=-1001,r=1001,mid;
75     while(l<=r) {
76     mid=(l+r)/2;
77     if(check(mid)) {
78         l=mid+1; ans=tot-mid*allow;
79     }else{
80         r=mid-1;
81     }
82     }
83     printf(OT,ans);
84 }
85
86 int main()
87 {
88   work();
89   return 0;
90 }
时间: 2024-10-05 04:22:30

BZOJ2654 tree的相关文章

WQS二分题集

WQS二分,一种优化一类特殊DP的方法. 很多最优化问题都是形如“一堆物品,取与不取之间有限制.现在规定只取k个,最大/小化总收益”. 这类问题最自然的想法是:设f[i][j]表示前i个取j个的最大收益,转移即可.复杂度O(n^2). 那么,如果在某些情况下,可以通过将问题稍作转化,变成一个不强制选k个的DP,而最后DP出来的最优解一定正好选了k个,那么问题就会简化很多. WQS二分就是基于这个思想. 首先考虑建一个二维坐标系,x轴是选的数的个数,y轴是最大收益,如果这个x-y图像有凸性,那么就

带权二分

带权二分 一种二分答案的套路,又叫做DP凸优化,wqs二分. 用来解决一类题目,要求某个要求出现K次,并且,可以很显然的发现,在改变相应权值的时候,对应出现的次数具有单调性.而且很显然,这种题一般满足一定的要求.而且一般权值为整数二分就可以,但是有的题需要实数二分...而且,边界条件通常很麻烦,调起来想摔电脑. 例题时间: BZOJ2654: tree 题目大意:给你一个图,里面有白色边和黑色边,问恰好有k条边白色边的最小生成树 直接贪心法肯定是错误的,因此,我们考虑带权二分. 给定一个选择白色

【BZOJ2654】tree 二分+最小生成树

[BZOJ2654]tree Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色边数. 接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色). Output 一行表示所求生成树的边权和. V<=50000,E<=100000,所有数据边权为[1,100]中的正整数. Sample Input 2 2 1

【bzoj2654】tree

Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色边数. 接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色). Output 一行表示所求生成树的边权和. V<=50000,E<=100000,所有数据边权为[1,100]中的正整数. Sample Input 2 2 1 0 1 1 1 0 1 2 0

【bzoj2654】 tree

http://www.lydsy.com/JudgeOnline/problem.php?id=2654 (题目链接) 今天考试题,以为是神题不可做,直接放弃了..没想到这么水.. 题意:给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树.题目保证有解. solution  我们考虑把白边的权值增加,因为无论白边的权值增加多少,最小生成树中的白边不会改变.所以我们二分每次把所有白边的权值增加多少,按边权大小排序后克鲁斯卡尔看选出的白边是否大于need.统

二分+最小生成树【bzoj2654】: tree

2654: tree 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 二分答案,然后跑最小生成树判断. 注意优先跑白色边. code: #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int wx=500017; inline int read(){ int sum=0,f=1; ch

【bzoj2654]】tree

给白色边都加上一个值,二分这个值,使得选取的白边数量减少 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> using namespace std; typedef long long LL; #define N 100010 struct Node { int x,y,

easyui js取消选中 Tree 指定节点

取消所有选中 var rootNodes = treeObject.tree('getRoots'); for ( var i = 0; i < rootNodes.length; i++) { var node = treeObject.tree('find', rootNodes[i].id); treeObject.tree('uncheck', node.target); }

Maximum Depth of Binary Tree

这道题为简单题 题目: Given a binary tree, find its maximum depth.The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 思路: 我是用递归做的,当然也可以用深搜和广搜,递归的话就是比较左右子树的深度然后返回 代码: 1 # Definition for a binary tre