@description@

给定 N 个点 M 条边的一张图。

每个点有两个属性 Ai, Bi,表示你需要至少 Ai 个士兵来攻占该点,向 i 点投放一个士兵需要 Bi 的花费。

每条边都有一个属性 Ci,表示如果该边的两个端点的士兵数量之和 >= Ci,那么这条边就被打通了(即士兵可以自由通过该边)。

士兵不会死亡。求攻占所有点的最小代价和。

Input

第一行包含两个整数 n, m (1 ≤ n,m ≤ 300000)。

接下来 n 行,每行两个整数 ai 与 bi (0 ≤ ai,bi ≤ 1000000)。

接下来 m 行,每行三个整数 si, fi 与 ci 描述一条边 (si, fi) (1 ≤ si,fi ≤ n, 0 ≤ ci ≤ 1000000)。

Output

输出一个整数,表示最小花费。

Example

standard input

3 2

10 5

20 10

10 3

1 2 22

2 3 200

standard output

140

@solution@

最终局面下,对于一个连通块,它对答案的贡献应为 min{bi} * max{max{ai}, max{cj}}。

因为我至少要投放 max{max{ai}, max{cj}} 这么多士兵才能保证连通且攻占全部点,那不如直接投放这个连通块费用最小的点那里。

当连通块对应的点集不变时,max{cj} 应尽量小才能获得更优的答案。

在 max{cj} 最小的情况下连通这个连通块,这显然就是最小生成树了(参考 kruskal 的算法过程)。

继续分析。当一个连通块的 max{ai, cj} 大于它邻接的某条边 k 的 ck 时,我加入 k 这条边显然不会更劣(max{ai, cj} 不变,min{b} 反而可能变小)。

还可以得到一个更严格的限制:当一个连通块的 max{cj} 大于它邻接的某条边 k 的 ck 时,加入 k 这条边依然不会更劣。

正确性,简单来说,就是 A*B + C*D >= min(A, C)*max(B, D)。假如 B <= D,则 min(A, C)*max(B, D) = min(A, C)*D <= C*D <= A*B + C*D。

那么考虑 ci 最大的那一条边。假如它被选中,根据上面的理论,其他边也会被选中。如果选中其他边产生了环,证明它不是一棵最小生成树,显然不合法。否则,我们可以算出此时的答案。

假如它不被选中,相当于求去除了这条边的最优值。这又递归成一个子问题。

但是这个太慢了。不如反过来,考虑 ci 从小到大枚举。

假如此时加入这条边,产生了环,与最小生成树矛盾,此时直接忽视第 i 条边(类 kruskal 的过程)。

否则,计算这条边连接的两个点集的 min{b}, max{a}。此时因为 i 的 ci 是最大的,所以直接取 max{ci, max{a}} 即可。

为了与不加入第 i 条边的最优值对比,我们对于每个点集再维护个 f,表示加入前 i-1 条边该点集的最优答案是什么。

@accepted code@

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef long long ll;
  5. const int MAXN = 300000;
  6. struct edge{
  7. int u, v; ll w;
  8. edge(int _u=0, int _v=0, ll _w=0) : u(_u), v(_v), w(_w) {}
  9. friend bool operator < (edge a, edge b) {
  10. return a.w < b.w;
  11. }
  12. }e[MAXN + 5];
  13. int fa[MAXN + 5];
  14. ll f[MAXN + 5], ma[MAXN + 5], mb[MAXN + 5];
  15. int find(int x) {
  16. return fa[x] = (fa[x] == x ? x : find(fa[x]));
  17. }
  18. void unite(int x, int y, ll w) {
  19. int fx = find(x), fy = find(y);
  20. if( fx != fy ) {
  21. mb[fy] = min(mb[fy], mb[fx]);
  22. ma[fy] = max(ma[fy], ma[fx]);
  23. f[fy] = min(f[fx] + f[fy], max(ma[fy], w)*mb[fy]);
  24. fa[fx] = fy;
  25. }
  26. }
  27. int main() {
  28. int n, m; scanf("%d%d", &n, &m);
  29. for(int i=1;i<=n;i++) scanf("%lld%lld", &ma[i], &mb[i]);
  30. for(int i=1;i<=m;i++) scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].w);
  31. for(int i=1;i<=n;i++) fa[i] = i, f[i] = ma[i]*mb[i];
  32. sort(e + 1, e + m + 1);
  33. for(int i=1;i<=m;i++) unite(e[i].u, e[i].v, e[i].w);
  34. ll ans = 0;
  35. for(int i=1;i<=n;i++)
  36. if( find(i) == i ) ans += f[i];
  37. printf("%lld\n", ans);
  38. }

@details@

感觉还是比较巧妙的题,运用了比较多的性质,写出来代码也不是很长。

(我没学过图论.jpg)

@gym - 101137K@ Knights of the Old Republic的更多相关文章

  1. 2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic(Kruskal思想)

    2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic 题意:有一张图,第i个点被占领需要ai个兵,而每个兵传送至该 ...

  2. 【Gym101137K】Knights of the Old Republic(生成树 DP)

    题目链接 大意 给定\(N\)个点\(M\)条边的一张图,其中: 每个点有两个属性\(A_i,B_i\),表示你需要至少\(A_i\)个士兵来攻占该点,而空投一个士兵至该点需要Bi的花费. 每条边都有 ...

  3. 2016-2017 ACM-ICPC, NEERC, Moscow Subregional Contest

    A. Altitude 从小到大加入每个数,用set查找前驱和后继即可. 时间复杂度$O(n\log n)$. #include <bits/stdc++.h> using namespa ...

  4. 3d引擎列表

    免费引擎 Agar - 一个高级图形应用程序框架,用于2D和3D游戏. Allegro library - 基于 C/C++ 的游戏引擎,支持图形,声音,输入,游戏时钟,浮点,压缩文件以及GUI. A ...

  5. Codeforces Gym 100650D Queens, Knights and Pawns 暴力

    Problem D: Queens, Knights and PawnsTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu ...

  6. Kernel Knights (Gym - 101480K)

    题目链接 #include <bits/stdc++.h> using namespace std; typedef long long ll; int a[200005]; //存放原始 ...

  7. Gym - 101480K_K - Kernel Knights (DFS)

    题意:有两队骑士各n人,每位骑士会挑战对方队伍的某一个位骑士. (可能相同) 要求找以一个区间s: 集合S中的骑士不会互相挑战. 每个集合外的骑士必定会被集合S内的某个骑士挑战. 题解:讲真被题目绕懵 ...

  8. Codeforces Gym100812 L. Knights without Fear and Reproach-扩展欧几里得(exgcd)

    补一篇以前的扩展欧几里得的题,发现以前写错了竟然也过了,可能数据水??? 这个题还是很有意思的,和队友吵了两天,一边吵一边发现问题??? L. Knights without Fear and Rep ...

  9. ACM: Gym 101047M Removing coins in Kem Kadrãn - 暴力

     Gym 101047M Removing coins in Kem Kadrãn Time Limit:2000MS     Memory Limit:65536KB     64bit IO Fo ...

随机推荐

  1. ES6学习笔记之字符串的扩展

    字符串的for of ES6 为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历. const str='abcd'; for(let s of str){ console.log(s ...

  2. centos安装消息队列beanstalkd

    起因:开始想在windows安装beanstalkd,可以找了很多资料都没有成功.最终还是妥协.在虚拟机上装一个centos系统,然后在centos上安装beanstalkd供windows使用 yu ...

  3. JNI初级:android studio生成so文件详细过程

    本文主要参考blog:http://blog.csdn.net/jkan2001/article/details/54316375 下面是本人结合blog生成so包过程中遇到一些问题和解决方法 (1) ...

  4. vmware三种网络模式配置(转载)

    虚拟机系统安装的是Linux系统 首先,在本机上查看所有网络配置连接,使用命令:ipconfig Microsoft Windows [版本 6.1.7600]版权所有 (c) 2009 Micros ...

  5. 在vscode中使用字体Cascadia Code

    下载字体 下载地址:github:https://github.com/microsoft/cascadia-code/releases 安装字体(windows10) 设置 > 个性化 > ...

  6. Linxu SSH登陆出现Access Denied错误的解决方法

    其实这个问题是从 SCP 过来的.用 SCP 在两台 Linux 服务器之间传送备份文件.输入完 root 密码后,总是出现 Permission denied, please try again.  ...

  7. react仿豆瓣

    最近公司在做一个自己内部的图片上传系统,目的是帮助设计人员方便上传图片,用的是vue技术,但是说到vue,可能要提到更早出来的react,react是facebook搞的一套语法糖,也是革命性的用组件 ...

  8. Java IO:字节流与字符流

    https://blog.csdn.net/my_truelove/article/details/53758412 字符和字节之间可以互相转化,中间的参照就是编码方式. 相当于给你一个密码本,按照这 ...

  9. QT_强杀进程

    #ifdef WIN32 bool res = false; HANDLE hToolHelp32Snapshot; hToolHelp32Snapshot = CreateToolhelp32Sna ...

  10. Android原生调用mui里面的js如何实现

    遍历所有运行中的webview页面,采用自带的SDK方法进行获取所有的IWebview.MUI中自带的webview是一个IWebviewArrayList<IWebview> webli ...