【生成树,堆】【CF1095F】 Make It Connected
Description
给定 \(n\) 个点,每个点有点权,连结两个点花费的代价为两点的点权和。另外有 \(m\) 条特殊边,参数为 \(x,y,z\)。意为如果你选择这条边,就可以花费 \(z\) 的代价将点 \(x\) 和点 \(y\) 连结起来,当然你也可以不选择这条边。求使整个图联通的最小代价
Input
第一行是两个整数,分别是点数 \(n\) 和特殊边的数量 \(m\)
下面一行 \(n\) 个数,第 \(i\) 个数代表点 \(i\) 的点权
下面 \(m\) 行,每行三个数 \(x,y,z\),代表一条特殊边
Output
输出一行一个整数,最小代价
Hint
\(1~\leq~n~\leq~2~\times~10^5~,0~\leq~m~\leq~2~\times~10^5\)
设第 \(i\) 个点的点权为 \(a_i\),第 \(j\) 条特殊边的边权为 \(z_j\),保证
\(1~\leq~a_i,z_j~\leq~10^{12}\)
保证特殊边的参数 \(x~\neq~y\)
Solution
显然这个题目是要求一个 MST (最小生成树),但是 \(O(n^2)\) 建图显然不可取。
我们考虑克鲁斯卡尔算法的本质:
有若干个联通块,每次寻找联通块间权值最小的边将之连结。
考虑对于本题来说,在不考虑特殊边的情况下,连结两个联通块,显然要分别选择两个联通块内点权最小的点连结。于是我们对每个集合维护点权最小的点,每次取出点权前两小的集合进行连边即可。维护点权前两小的集合显然可以用一个堆做。
考虑有特殊边怎么办:
我们把特殊边排序,每次比较当前的特殊边的权值小还是前两个联通块的点权小,选择更小的合并。
注意处理一下当前选出的两个点在一个集合中的情况。
因为一共要做 \(O(n)\) 次,每次会有 \(O(1)\) 次对堆的插入和删除操作,于是复杂度 \(O(n \log n)\)
Code
#include <cstdio>
#include <queue>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long
typedef long long int ll;
namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}
template <typename T>
inline void qr(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}
template <typename T>
inline void ReadDb(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
}
namespace OPT {
char buf[120];
}
template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
rg int top=0;
do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}
const int maxn = 200010;
const int maxm = 400010;
struct Edge {
int from, to;
ll v;
inline bool operator<(const Edge &_others) const {
return this->v < _others.v;
}
};
Edge edge[maxm];
int n, m;
int ufs[maxn], vec[maxn], rk[maxn];
ll ans;
ll MU[maxn];
struct Zay {
int id;
ll v;
inline bool operator<(const Zay &_others) const {
return this->v > _others.v;
}
};
std::priority_queue<Zay>Q;
int find(ci x) {return ufs[x] == x ? x : ufs[x] = find(ufs[x]);}
int main() {
freopen("1.in", "r", stdin);
qr(n); qr(m);
for (rg int i = 1; i <= n; ++i) qr(MU[i]);
for (rg int i = 1; i <= m; ++i) {
qr(edge[i].from); qr(edge[i].to); qr(edge[i].v);
}
std::sort(edge + 1, edge + 1 + m);
edge[m + 1].v = 1ll << 62;
for (rg int i = 1; i <= n; ++i) ufs[i] = i, vec[i] = i, rk[i] = 1, Q.push((Zay){i, MU[i]});
for (rg int i = 1, cur = 1; i < n; ++i) {
while ((cur <= m) && (find(edge[cur].from) == find(edge[cur].to))) ++cur;
Zay t1 = Q.top(); Q.pop(); Zay t2 = Q.top(); Q.pop();
while (find(t1.id) == find(t2.id)) {t2 = Q.top(); Q.pop();}
if ((t1.v + t2.v) <= edge[cur].v) {
int fa = find(t1.id), fb = find(t2.id);
ans += t1.v + t2.v;
if (rk[fa] < rk[fb]) ufs[fb] = fa;
else if (rk[fa] > rk[fb]) ufs[fa] = fb;
else ufs[fa] = fb, ++rk[fb];
Q.push((Zay){find(fa), t1.v});
vec[find(fa)] = vec[fa];
} else {
int fa = find(edge[cur].from), fb = find(edge[cur].to);
ans += edge[cur].v;
if (rk[fa] < rk[fb]) ufs[fb] = fa;
else if (rk[fa] > rk[fb]) ufs[fa] = fb;
else ufs[fa] = fb, ++rk[fb];
Q.push((Zay){find(fa), MU[vec[fa]]});
vec[find(fa)] = vec[fa];
Q.push(t1); Q.push(t2);
}
}
qw(ans, '\n', true);
return 0;
}
【生成树,堆】【CF1095F】 Make It Connected的更多相关文章
- [CF1095F]Make It Connected
题目大意:给你$n(n\leqslant2\times10^5)$个点和$m(m\leqslant2\times10^5)$条边,第$i$个点点权为$a_i$.连接$u,v$两个点的代价为$a_u+a ...
- 【CF1095F】 Make It Connected(最小生成树)
题目链接 如果没有特殊边的话显然答案就是权值最小的点向其他所有点连边. 所以把特殊边和权值最小的点向其他点连的边丢一起跑最小生成树就行了. #include <cstdio> #inclu ...
- 题解 CF1095F 【Make It Connected】
题意简述 \(n\)( \(1≤n≤2×10^5\) )个点,每个点 \(i\) 有一个点权 \(a_i\) ( \(1≤a_i≤2×10^{12}\) ),将两个点 \(i\),\(j\) 直接相连 ...
- POJ 2728 Desert King 最优比率生成树
Desert King Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 20978 Accepted: 5898 [Des ...
- POJ 2728 Desert King(最优比例生成树 二分 | Dinkelbach迭代法)
Desert King Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 25310 Accepted: 7022 Desc ...
- [POJ2728] Desert King 解题报告(最优比率生成树)
题目描述: David the Great has just become the king of a desert country. To win the respect of his people ...
- PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由
03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...
- ACM:Pseudoforest-并查集-最大生成树-解题报
Pseudoforest Time Limit:5000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Submit Status ...
- hdu 3367 Pseudoforest(最大生成树)
Pseudoforest Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) To ...
随机推荐
- python爬取淘宝华为手机
import re from selenium import webdriver from selenium.common.exceptions import TimeoutException fro ...
- mysql 性能优化 20 条建议
MySQL性能优化的最佳20+条经验 2009年11月27日陈皓发表评论阅读评论100,946 人阅读 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性 ...
- “Hello World!“”团队第五周召开的第二次会议
今天是我们团队“Hello World!”团队第五周召开的第二次会议.也祝大家双十一快乐~~博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七 ...
- Codeforces Round #345 (Div. 1) C. Table Compression dp+并查集
题目链接: http://codeforces.com/problemset/problem/650/C C. Table Compression time limit per test4 secon ...
- C语言的知识与能力予以自评
看到一个问卷不错,拟作为第三次作业的部分内容. 你对自己的未来有什么规划?做了哪些准备?答:多学习几门生存技巧,首先先学会碰壁. 你认为什么是学习?学习有什么用?现在学习动力如何?为什么?答:学习是人 ...
- android入门 — 多线程(一)
android中的一些耗时操作,例如网络请求,如果不能及时响应,就会导致主线程被阻塞,出现ANR,非常影响用户体验,所以一些耗时的操作,我们会想办法放在子线程中去完成. android的UI操作并不是 ...
- iOS- Swift:使用FMDB进行数据库操作(线程安全:增删改查)
1.前言 GitHub上2000多颗星的FMDB数据库框架想来大家都很熟悉, 今天用Swift对其进行了一个完成的数据存储读流程 写完之后用博客分享之,与大家一起交流, 希望对需要的朋友提供些帮助 ...
- vue知识拓展
组件 *组件里面如果要放数据: data必须是函数的形式,函数必须返回一个对象(json),有的时候我们自己创建的组件需要使用到自己的数据,此外组建中也可以放入自己的其他的比如事件之类的 ...
- java读取xls和xlsx数据作为数据驱动来用
java读取Excle代码 拿来可以直接使用 :针对xls 和 xlsx package dataProvider; import java.io.File; import java.io.FileI ...
- selenium Object Page 设计模式理解及实现!
Page Object模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在Selenium测试页面中可以通 ...