如果把每个方案的看做二维坐标
实际上我们就是要找到下凸壳上的所有点维护答案
考虑先找出最小的点和最小的点
这2个点一定在下凸壳上
然后我们可以用这条直线从下往上切,切到的第一个点也肯定在凸包上
然后递归继续切
同时维护乘积最小值即可
由于方案的点集分布较为均匀
所以下凸壳上点期望个数只有个
所以复杂度是对的
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
const int mod=998244353,g=3;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=205,M=10005;
struct pt{
int x,y;
pt(int _x=0,int _y=0):x(_x),y(_y){}
friend inline pt operator +(cs pt &a,cs pt &b){
return pt(a.x+b.x,a.y+b.y);
}
friend inline pt operator -(cs pt &a,cs pt &b){
return pt(a.x-b.x,a.y-b.y);
}
friend inline int operator *(cs pt &a,cs pt &b){
return 1ll*a.x*b.y-1ll*a.y*b.x;
}
friend inline bool operator <(cs pt &a,cs pt &b){
return 1ll*a.x*a.y==1ll*b.x*b.y?(a.x<b.x):(1ll*a.x*a.y<1ll*b.x*b.y);
}
inline int dis(){
return x*x+y*y;
}
}ans;
struct edge{
int u,v;ll a,b,c;
friend inline bool operator <(cs edge &a,cs edge &b){
return a.c<b.c;
}
}e[M];
int n,m;
int fa[N];
inline int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline pt kruscal(){
for(int i=1;i<=n;i++)fa[i]=i;
sort(e+1,e+m+1);pt res;
for(int cnt=0,i=1;i<=m&&cnt<n-1;i++){
int f1=find(e[i].u),f2=find(e[i].v);
if(f1!=f2)fa[f1]=f2,cnt++,res=res+pt(e[i].a,e[i].b);
}
if(res<ans)ans=res;
return res;
}
inline void calc(cs pt &A,cs pt &B){
for(int i=1;i<=m;i++)e[i].c=1ll*e[i].b*(B.x-A.x)+1ll*e[i].a*(A.y-B.y);
pt res=kruscal();
if((A-B)*(res-B)<=0)return;
calc(A,res),calc(res,B);
}
int main(){
ans=pt(1e9,1e9);
n=read(),m=read();
for(int i=1;i<=m;i++){
e[i].u=read()+1,e[i].v=read()+1,e[i].a=read(),e[i].b=read();
}
for(int i=1;i<=m;i++)e[i].c=e[i].a;
pt A=kruscal();
for(int i=1;i<=m;i++)e[i].c=e[i].b;
pt B=kruscal();
calc(A,B);
cout<<ans.x<<" "<<ans.y<<'
';
}