[国家集训队2]Tree I
Posted alecli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[国家集训队2]Tree I相关的知识,希望对你有一定的参考价值。
题意
思考
(WQS) 二分,第一次做,感觉细节有点多。
由于要求选 (need) 条白边,我们考虑每次给所有白边加上一个权值,再与黑边一起做生成树,这样就可以限制我们加入白边的个数了,但是这样我们还存在一个问题,如果有白边等于黑边权值,我们可能会先统计黑边,造成白边达不到 (need) 条的情况,我们只用在排序时加上第二关键字,优先选择白边即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x * f;
}
const int M = 100010;
const int N = 50050;
struct node{
int from, to, dis, op, now;
}edge[M << 1];
bool cmp(node a, node b){
return (a.now == b.now) ? a.op < b.op : a.now < b.now;
}
int fa[N];
int n, m, need, ans, sum, js;
int findx(int x){
if(fa[x] == x) return x;
return fa[x] = findx(fa[x]);
}
void mergex(int x, int y){
int fx = findx(x), fy = findx(y);
if(fx == fy) return;
fa[fx] = fy;
}
bool check(int del){
js = 0; sum = 0;
for(int i=1; i<=n; i++) fa[i] = i;
for(int i=1; i<=m; i++){
edge[i].now = edge[i].dis;
if(edge[i].op == 0) edge[i].now += del;
}
sort(edge+1, edge+m+1, cmp);
for(int i=1; i<=m; i++){
int u = edge[i].from, v = edge[i].to;
int fu = findx(u), fv = findx(v);
if(fu != fv){
mergex(u, v); sum += edge[i].dis;
if(edge[i].op == 0) js ++;
}
}
return js >= need;
}
int main(){
n = read(), m = read(), need = read();
for(int i=1; i<=m; i++){
edge[i].from = read(), edge[i].to = read(), edge[i].dis = read(), edge[i].op = read();
edge[i].from ++, edge[i].to ++;
if(edge[i].op == 1) edge[i].now = edge[i].dis;
}
int l = -100, r = 100;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid)){
l = mid + 1;
ans = sum;
}
else r = mid - 1;
}
cout<<ans;
return 0;
}
总结
注意二分的判断条件是大于等于 (need) ,以及排序时注意第二关键字以避免无法出解。
以上是关于[国家集训队2]Tree I的主要内容,如果未能解决你的问题,请参考以下文章