【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


这题挺有趣的

我们先不考虑白边的限制,那么就是一个最小生成树。

那么我们考虑限制白边数量为一,我们对执行最小生成树的方案做修改:把白边的边权增加。这样就会尽量少地添加白边。

然后我们考虑增加白边的数量,二分即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=100050;
struct Edge{
    int from,to,val,col;
}edge[N];
int from[N],to[N],val[N],col[N];
int fa[N];
int n,m,Need,ans,tot,cnt;
inline void read(int &s){
    int flag=1;s=0;char ch=getchar();
    while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)flag=-1;ch=getchar();}
    while(ch>=‘0‘ && ch<=‘9‘){s=s*10+ch-‘0‘;ch=getchar();}
    s*=flag;
}
inline bool operator < (const Edge &a,const Edge &b){return a.val==b.val ? a.col<b.col : a.val<b.val;}
int find(int x){return x==fa[x] ? fa[x] : fa[x]=find(fa[x]);}
bool check(int x){
    tot=cnt=0;
    for(int i=1;i<=n;++i)fa[i]=i;
    for(int i=1;i<=m;++i){
        edge[i].from=from[i];edge[i].to=to[i];edge[i].val=val[i];edge[i].col=col[i];
        if(!col[i])edge[i].val+=x;
    }
    sort(edge+1,edge+m+1);
    for(int i=1;i<=m;++i){
        int fx=find(edge[i].from),fy=find(edge[i].to);
        if(fx!=fy){
            fa[fx]=fy;
            tot+=edge[i].val;
            if(!edge[i].col)++cnt;
        }
    }
    return cnt>=Need;
}
int main(){
    read(n);read(m);read(Need);
    for(int i=1;i<=m;++i){
        read(from[i]);read(to[i]);read(val[i]);read(col[i]);
        ++from[i];++to[i];
    }
    int l=-105,r=105;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))l=mid+1,ans=tot-Need*mid;
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

bzoj2654

时间: 2024-12-16 14:01:01

【bzoj2654】tree的相关文章

【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

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,

【BZOJ4987】Tree 树形DP

[BZOJ4987]Tree Description 从前有棵树. 找出K个点A1,A2,…,Ak. 使得∑dis(AiAi+1),(1<=i<=K-1)最小. Input 第一行两个正整数n,k,表示数的顶点数和需要选出的点个数. 接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边. I<=k<=n. l<x,y<=n 1<=z<=10^5 n <= 3000 Output 一行一个整数,表示最小的距离和. Sample I

【POJ3237】Tree 树链剖分+线段树

[POJ3237]Tree Description You are given a tree with N nodes. The tree's nodes are numbered 1 through N and its edges are numbered 1 through N ? 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. Th

【Luogu1501】Tree(Link-Cut Tree)

[Luogu1501]Tree(Link-Cut Tree) 题面 洛谷 题解 \(LCT\)版子题 看到了顺手敲一下而已 注意一下,别乘爆了 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map>

【HDU5909】Tree Cutting(FWT)

[HDU5909]Tree Cutting(FWT) 题面 vjudge 题目大意: 给你一棵\(n\)个节点的树,每个节点都有一个小于\(m\)的权值 定义一棵子树的权值为所有节点的异或和,问权值为\(0..m-1\)的所有子树的个数 题解 考虑\(dp\) 设\(f[i][j]\)表示以\(i\)为根节点的子树中,异或和为\(j\)的子树的个数 很显然,每次合并就是两个\(dp\)值做\(xor\)卷积 那么直接用\(FWT\)优化就行了 #include<iostream> #inclu

点分治【bzoj1468】 Tree

点分治[bzoj1468] Tree Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k 点分治开始入门. 点分治,主要是解决形如:给你一棵树,求树上满足XX条件的点对的对数. 所以说应对的问题很多时候都和树形DP相同. 首先告诉自己,分治是高效的算法. 想一下,平时在面对普通的分治问题,每次肯定都是