CSP-S 模拟 19/10/09

T1:背包模板
T2:分数规划+单调队列模板
T3:华莱士
题意:选一些边并定下方向,使得每个点入度为 1,问选出来的最小边权和
发现我们可以先把这些边选出来,然后再定方向
我们发现一些性质:一个环只可能出不可能进,也就是我们最后选出来的图环两两之间没有边
脑补一些最后选出来的边的模型,就是基环树,环,它们之间不一定联通
考虑最小生成树一般的贪心
如果当前的两个点不联通,加上
如果当前的两个点联通,但当前连通块还没有环,标记一下并加上,如果有环,显然加上不合法
如果当前两个点不连通但两个点的连通块都有环,显然加上不合法
把环的标记打在并查集的祖先上即可

#include<bits/stdc++.h>
#define N 500050
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
	while(isdigit(ch)) cnt = cnt*10 + ch-'0', ch = getchar();
	return cnt * f;
}
typedef long long ll;
struct Node{ int u, v, w; }e[N];
bool cmp(Node a, Node b){ return a.w < b.w;}
int n, m;
int fa[N]; bool cir[N];
int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]);}
int main(){
	n = read(), m = read();
	for(int i = 1; i <= n; i++) fa[i] = i;
	for(int i = 1; i <= m; i++){
		e[i].u = read(); e[i].v = read(); e[i].w = read();
	} sort(e + 1, e + m + 1, cmp);
	int cnt = 0; ll ans = 0;
	for(int i = 1; i <= m; i++){
		int u = e[i].u, v = e[i].v, fx = find(u), fy = find(v);
		if(fx == fy){ if(cir[fx]) continue; cir[fx] = true; ++cnt; ans += (ll)e[i].w;}
		else{ if(cir[fx] && cir[fy]) continue; fa[fx] = fy; cir[fy] |= cir[fx]; ++cnt; ans += (ll)e[i].w; }
	} 
	if(cnt != n){ puts("No"); return 0;}
	cout << ans; return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值