洛谷题面传送门

大概是一个比较 trivial 的小 trick?学过了就不要忘了哦(

莫名奇妙地想到了 yyq 的”hot tea 不常有,做过了就不能再错过了“

首先看到这种二维问题我们可以很自然地想到将它们映射到一个二维平面上,即我们将 \(\sum\limits_{e\in E}a_e\) 看作横坐标 \(x\),将 \(\sum\limits_{e\in E}b_e\) 看作纵坐标 \(y\),那么我们所求即是全部生成树表示的点当中横纵坐标之积最大的点。显然这些点肯定都在所有点组成的下凸壳上,因此我们只用求出下凸壳上的所有点然后依次更新答案即可。

那么怎么求下凸壳上的点呢?我们考虑分治,考虑求出所有点当中横坐标最小的点 \(A\) 和纵坐标最小的点 \(B\)——这个可以通过将边权赋为 \(a_e\) 和 \(b_e\) 分别求一遍最小生成树求出,那么我们考虑求出满足 \(C\) 在 \(AB\) 左下方且 \(S_{\triangle ABC}\) 最大的点 \(C\)——由于 \(C\) 在 \(AB\) 左下方,根据计算几何那一套理论,\(S_{\triangle ABC}\) 最大即意味着 \(\vec{BA}\times\vec{BC}\) 最大,而 \(\vec{BA}\times\vec{BC}=(x_A-x_B)(y_C-y_B)-(x_C-x_B)(y_A-y_B)\),将括号打开,与 \(C\) 无关的放一边可以得到 \(\vec{BA}\times\vec{BC}\) 最大又意味着 \((x_A-x_B)y_C-(y_A-y_B)x_C\) 最大,因此考虑将每条边边权赋为 \((x_B-x_A)b_e-(y_A-y_B)a_e\) 然后跑一遍 MST 即可求出点 \(C\),如果我们发现求出的点 \(C\) 在 \(AB\) 右上方那直接 return 掉即可,否则继续递归处理 \((A,C)\) 和 \((C,B)\)。

据说用了个什么 QuickHull 的求凸包算法,凸壳上的点数最多是值域的 \(\dfrac{2}{3}\) 次方,因此复杂度就是 \((na)^{2/3}·n\log n\),但是显然证明就不是我的事了(

不知道能不能推广到三维.jpg

  1. const int MAXN=200;
  2. const int MAXM=1e4;
  3. struct edge{int u,v,w;} e[MAXM+5];
  4. int n,m,a[MAXM+5],b[MAXM+5],f[MAXN+5];
  5. int find(int x){return (!f[x])?x:f[x]=find(f[x]);}
  6. void merge(int x,int y){x=find(x);y=find(y);f[x]=y;}
  7. int ord[MAXM+5];pii ans=mp(0x3f3f3f3f,0x3f3f3f3f);
  8. bool cmp(int x,int y){return e[x].w<e[y].w;}
  9. pii kruskal(){
  10. memset(f,0,sizeof(f));for(int i=1;i<=m;i++) ord[i]=i;
  11. sort(ord+1,ord+m+1,cmp);int suma=0,sumb=0;
  12. for(int i=1;i<=m;i++){
  13. if(find(e[ord[i]].u)==find(e[ord[i]].v)) continue;
  14. merge(e[ord[i]].u,e[ord[i]].v);
  15. suma+=a[ord[i]];sumb+=b[ord[i]];
  16. } if(1ll*suma*sumb<1ll*ans.fi*ans.se||(1ll*suma*sumb==1ll*ans.fi*ans.se&&suma<ans.fi))
  17. ans=mp(suma,sumb);
  18. return mp(suma,sumb);
  19. }
  20. void solve(pii x,pii y){
  21. for(int i=1;i<=m;i++) e[i].w=b[i]*(y.fi-x.fi)+a[i]*(x.se-y.se);pii z=kruskal();
  22. if(1ll*(x.fi-y.fi)*(x.se-z.se)-1ll*(x.se-y.se)*(x.fi-z.fi)>=0) return;
  23. solve(x,z);solve(z,y);
  24. }
  25. int main(){
  26. scanf("%d%d",&n,&m);
  27. for(int i=1;i<=m;i++){
  28. scanf("%d%d%d%d",&e[i].u,&e[i].v,&a[i],&b[i]);
  29. ++e[i].u;++e[i].v;
  30. } pii x,y;
  31. for(int i=1;i<=m;i++) e[i].w=a[i];x=kruskal();
  32. for(int i=1;i<=m;i++) e[i].w=b[i];y=kruskal();
  33. solve(x,y);printf("%d %d\n",ans.fi,ans.se);
  34. return 0;
  35. }

洛谷 P5540 - [BalkanOI2011] timeismoney | 最小乘积生成树(最小生成树)的更多相关文章

  1. bzoj2395[Balkan 2011]Timeismoney最小乘积生成树

    所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也 ...

  2. 【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树

    链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网 ...

  3. Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)

    问题描述 每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树 Sol 把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) ...

  4. P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】

    正题 题目链接:https://www.luogu.com.cn/problem/P5540 题目大意 给出\(n\)个点\(m\)条边边权是一个二元组\((a_i,b_i)\),求出一棵生成树最小化 ...

  5. bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 如果把 \( \sum t \) 作为 x 坐标,\( \sum c \) 作为 y ...

  6. bzoj 2395 Timeismoney —— 最小乘积生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 参考博客:https://www.cnblogs.com/autsky-jadek/p ...

  7. Luogu5540 最小乘积生成树

    Luogu5540 最小乘积生成树 题目链接:洛谷 题目描述:对于一个\(n\)个点\(m\)条边的无向连通图,每条边有两个边权\(a_i,b_i\),求使\((\sum a_i)\times (\s ...

  8. HDU5697 刷题计划 dp+最小乘积生成树

    分析:就是不断递归寻找靠近边界的最优解 学习博客(必须先看这个): 1:http://www.cnblogs.com/autsky-jadek/p/3959446.html 2:http://blog ...

  9. 洛谷P4014 分配问题【最小/大费用流】题解+AC代码

    洛谷P4014 分配问题[最小/大费用流]题解+AC代码 题目描述 有 n 件工作要分配给 n 个人做.第 i 个人做第 j 件工作产生的效益为c ij. 试设计一个将 n 件工作分配给 n 个人做的 ...

随机推荐

  1. javascript-jquery对象的事件处理

    一.页面加载 1.页面加载顺序:先加载<head></head>之间的内容,然后加载<body></body>之间的内容 直接在head之间书写jque ...

  2. Python绘制Excel图表

    今天讲解下如何使用Python绘制各种Excel图表,下面我们以绘制饼状图.柱状图.水平图.气泡图.2D面积图.3D面积图为例来说明. import openpyxlfrom openpyxl imp ...

  3. ORB_SLAM3 -- 配置安装

    安装环境 Ubuntu20.04 ORB_SLAM3依赖项安装 opencv3 ORB_SLAM3可用opencv3或opencv4编译,作者这里安装测试了opencv3 Step1: 安装openc ...

  4. String直接赋字符串和new String的区别

    String A="ABC"; String B=new String("ABC"); String A = "ABC";内存会去查找常量池 ...

  5. VS2019、Qt5.12及QGis3.16开发常见问题汇总

    在C++.Qt软件开发过程中,常常遇到一些编译错误或警告:本文将VS2019.Qt5.12.10和QGis3.16.10的二次开发过程常见的问题做了整理,供大家参考,也便于日后查阅.该内容分为四部分: ...

  6. 主集天线和分集天线——4G天线技术

    主集天线和分集天线 分集接收技术是一项主要的抗衰落技术,可以大大提高多径衰落信道传输下的可靠性,在实际的移动通信系统中,移动台常常工作在城市建筑群或其他复杂的地理环境中,而且移动的速度和方向是任意的. ...

  7. CODING —— 云原生时代的研发工具领跑者

    本文为 CODING 创始人兼 CEO 张海龙在腾讯云 CIF 工程效能峰会上所做的分享. 文末可前往峰会官网,观看回放并下载 PPT. 大家上午好,很高兴能有机会与大家分享 CODING 最近的一些 ...

  8. 【做题记录】DP 杂题

    P2577 [ZJOI2004]午餐 $\texttt{solution}$ 想到贪心: 吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 状态: \(f[i][j]\) 表示前 \(i\ ...

  9. songwenxin

    # -*- coding: utf-8 -*- import wx from modelmngr_frame import MyFrame1 ############################# ...

  10. 并发编程从零开始(十四)-Executors工具类

    并发编程从零开始(十四)-Executors工具类 12 Executors工具类 concurrent包提供了Executors工具类,利用它可以创建各种不同类型的线程池 12.1 四种对比 单线程 ...