http://www.lydsy.com/JudgeOnline/problem.php?id=2395
考虑在二维坐标系上
一种生成树方案\((cost, time)\)对应一个点
答案一定是在下凸包上的一段
我们考虑如何找到这个下凸包
首先找到两个初始点\(a, b\)
分别对应以\(cost\), \(time\)为最优
然后我们可以在\(a~b\)之间进行二分
找到离\(ab\)最远的点\(c\)
最小化\(\vec{ab} \times \vec{ac}\)也就是面积
然后对于每一条边 重新赋值
值为对答案的贡献 然后就枚举了所有下凸包的点
复杂度是\(O(S n \log n)\)
\(S\)是点对数 知乎上说是\(m^2\)级别的
#include<bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cout << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ i)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0;char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
for(int i = 1; i <= n; i ++)
cout << a[i] << " ";
puts("");
}
const int N = 233;
const int M = 11233;
struct E {
int u, v, x, y, w;
inline void in(void) {
read(u); read(v); read(x); read(y);
++ u; ++ v;
}
}e[M];
struct Node {
int x, y;
Node(int _x = 0, int _y = 0) {
x = _x; y = _y;
}
inline void ovo(void) {
cout << x << " " << y << "\n";
}
}ans, minx, miny;
int n, m, pre[N];
inline Node operator - (Node a, Node b) {
return Node(a.x - b.x, a.y - b.y);
}
inline int crs(Node a, Node b) {
return a.x * b.y - a.y * b.x;
}
inline int find(int u) {
return pre[u] == u ? u : pre[u] = find(pre[u]);
}
inline bool cmp_w(E a, E b) {
return a.w < b.w;
}
inline Node doit(void) {
for(int i = 1; i <= n; i ++)
pre[i] = i;
sort(e + 1, e + m + 1, cmp_w);
Node now;
for(int i = 1; i <= m; i ++) {
int fx = find(e[i].u);
int fy = find(e[i].v);
if(fx != fy) {
pre[fx] = fy;
now.x += e[i].x;
now.y += e[i].y;
}
}
if(!ans.x || (ans.x * ans.y > now.x * now.y))
ans = now;
return now;
}
inline void work(Node a, Node b) {
for(int i = 1; i <= m; i ++)
e[i].w = e[i].y * (b.x - a.x) - e[i].x * (b.y - a.y);
Node c = doit();
if(crs(c - a, b - a) <= 0)
return ;
work(a, c); work(c, b);
}
main(void) {
read(n); read(m);
for(int i = 1; i <= m; i ++)
e[i].in();
for(int i = 1; i <= m; i ++)
e[i].w = e[i].x;
minx = doit();
for(int i = 1; i <= m; i ++)
e[i].w = e[i].y;
miny = doit();
work(minx, miny);
cout << ans.x << " " << ans.y << "\n";
}