洛谷 P5540 - [BalkanOI2011] timeismoney | 最小乘积生成树(最小生成树)
大概是一个比较 trivial 的小 trick?学过了就不要忘了哦(
莫名奇妙地想到了 yyq 的”hot tea 不常有,做过了就不能再错过了“
首先看到这种二维问题我们可以很自然地想到将它们映射到一个二维平面上,即我们将 ∑e∈Eae∑e∈Eae 看作横坐标 xx,将 ∑e∈Ebe∑e∈Ebe 看作纵坐标 yy,那么我们所求即是全部生成树表示的点当中横纵坐标之积最大的点。显然这些点肯定都在所有点组成的下凸壳上,因此我们只用求出下凸壳上的所有点然后依次更新答案即可。
那么怎么求下凸壳上的点呢?我们考虑分治,考虑求出所有点当中横坐标最小的点 AA 和纵坐标最小的点 BB——这个可以通过将边权赋为 aeae 和 bebe 分别求一遍最小生成树求出,那么我们考虑求出满足 CC 在 ABAB 左下方且 S△ABCS△ABC 最大的点 CC——由于 CC 在 ABAB 左下方,根据计算几何那一套理论,S△ABCS△ABC 最大即意味着 →BA×→BC→BA×→BC 最大,而 →BA×→BC=(xA−xB)(yC−yB)−(xC−xB)(yA−yB)→BA×→BC=(xA−xB)(yC−yB)−(xC−xB)(yA−yB),将括号打开,与 CC 无关的放一边可以得到 →BA×→BC→BA×→BC 最大又意味着 (xA−xB)yC−(yA−yB)xC(xA−xB)yC−(yA−yB)xC 最大,因此考虑将每条边边权赋为 (xB−xA)be−(yA−yB)ae(xB−xA)be−(yA−yB)ae 然后跑一遍 MST 即可求出点 CC,如果我们发现求出的点 CC 在 ABAB 右上方那直接 return 掉即可,否则继续递归处理 (A,C)(A,C) 和 (C,B)(C,B)。
据说用了个什么 QuickHull 的求凸包算法,凸壳上的点数最多是值域的 2323 次方,因此复杂度就是 (na)2/3·nlogn(na)2/3⋅nlogn,但是显然证明就不是我的事了(
不知道能不能推广到三维.jpg
const int MAXN=200; const int MAXM=1e4; struct edge{int u,v,w;} e[MAXM+5]; int n,m,a[MAXM+5],b[MAXM+5],f[MAXN+5]; int find(int x){return (!f[x])?x:f[x]=find(f[x]);} void merge(int x,int y){x=find(x);y=find(y);f[x]=y;} int ord[MAXM+5];pii ans=mp(0x3f3f3f3f,0x3f3f3f3f); bool cmp(int x,int y){return e[x].w<e[y].w;} pii kruskal(){ memset(f,0,sizeof(f));for(int i=1;i<=m;i++) ord[i]=i; sort(ord+1,ord+m+1,cmp);int suma=0,sumb=0; for(int i=1;i<=m;i++){ if(find(e[ord[i]].u)==find(e[ord[i]].v)) continue; merge(e[ord[i]].u,e[ord[i]].v); suma+=a[ord[i]];sumb+=b[ord[i]]; } if(1ll*suma*sumb<1ll*ans.fi*ans.se||(1ll*suma*sumb==1ll*ans.fi*ans.se&&suma<ans.fi)) ans=mp(suma,sumb); return mp(suma,sumb); } void solve(pii x,pii y){ 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(); if(1ll*(x.fi-y.fi)*(x.se-z.se)-1ll*(x.se-y.se)*(x.fi-z.fi)>=0) return; solve(x,z);solve(z,y); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&e[i].u,&e[i].v,&a[i],&b[i]); ++e[i].u;++e[i].v; } pii x,y; for(int i=1;i<=m;i++) e[i].w=a[i];x=kruskal(); for(int i=1;i<=m;i++) e[i].w=b[i];y=kruskal(); solve(x,y);printf("%d %d\n",ans.fi,ans.se); return 0; }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· Vite CVE-2025-30208 安全漏洞
· 《HelloGitHub》第 108 期
· MQ 如何保证数据一致性?
· 一个基于 .NET 开源免费的异地组网和内网穿透工具