分组赛时学到的最小乘积生成树模型,感觉这个思路非常神,可以说是数形结合的经典问题
由于生成树有两个权值,我们把每个生成树的权值表示成点坐标(sa,sb)
显然我们知道,乘积最小,那么点必然落在下凸壳上
但由于点太多,graham之类要先知道所有点再求凸包的算法就失效了
于是我们使用quickhull算法,这个算法只要知道凸包上的两个点就可以扩展出下一个点,然后不断分治即可扩展出所有点
显然,以a为关键字和以b为关键字的最小生成树一定是凸包上的两个点i,j
根据quickhull算法,下一个凸包上的点就是离直线ij距离最大的点
转化一下,就是与ij垂直的向量点积最小的点
显然我们只要以此为关键字求最小生成树即可
这样我们不断分治下去,直到无法扩展为止,这样就找到了答案
但我好像被卡常了(还是写的太囧……),总之tle了……
1 type node=record 2 x,y,w,a,b:longint; 3 end; 4 point=record 5 x,y:longint; 6 end; 7 8 var e:array[0..10010] of node; 9 fa:array[0..210] of longint; 10 i,n,m:longint; 11 ans,p1,p2:point; 12 13 function getf(x:longint):longint; 14 begin 15 if fa[x]<>x then fa[x]:=getf(fa[x]); 16 exit(fa[x]); 17 end; 18 19 procedure swap(var a,b:node); 20 var c:node; 21 begin 22 c:=a; 23 a:=b; 24 b:=c; 25 end; 26 27 function cmp(x,y:node):boolean; 28 begin 29 if x.w=y.w then exit(x.a<y.a); 30 exit(x.w<y.w); 31 end; 32 33 procedure sort(l,r:longint); 34 var i,j:longint; 35 x:node; 36 begin 37 i:=l; 38 j:=r; 39 x:=e[(l+r) shr 1]; 40 repeat 41 while cmp(e[i],x) do inc(i); 42 while cmp(x,e[j]) do dec(j); 43 if not(i>j) then 44 begin 45 swap(e[i],e[j]); 46 inc(i); 47 dec(j); 48 end; 49 until i>j; 50 if l<j then sort(l,j); 51 if i<r then sort(i,r); 52 end; 53 54 function mintree:point; 55 var i,j,sa,sb,x,y:longint; 56 begin 57 {for j:=1 to m do 58 writeln(e[j].w); } 59 j:=0; 60 sa:=0; 61 sb:=0; 62 for i:=1 to n do 63 fa[i]:=i; 64 i:=0; 65 while i<n-1 do 66 begin 67 inc(j); 68 x:=getf(e[j].x); 69 y:=getf(e[j].y); 70 if x<>y then 71 begin 72 fa[x]:=y; 73 sa:=sa+e[j].a; 74 sb:=sb+e[j].b; 75 inc(i); 76 end; 77 end; 78 mintree.x:=sa; 79 mintree.y:=sb; 80 if (int64(ans.x)*int64(ans.y)>int64(sa)*int64(sb)) or (int64(ans.x)*int64(ans.y)=int64(sa)*int64(sb)) and (ans.x>sa) then 81 begin 82 ans.x:=sa; 83 ans.y:=sb; 84 end; 85 end; 86 87 function cross(a,b,c:point):int64; 88 begin 89 exit(int64(a.x-c.x)*int64(b.y-c.y)-int64(a.y-c.y)*int64(b.x-c.x)); 90 end; 91 92 procedure work(p1,p2:point); 93 var i:longint; 94 p:point; 95 96 begin 97 for i:=1 to m do 98 e[i].w:=e[i].a*(p1.y-p2.y)+e[i].b*(p2.x-p1.x); 99 sort(1,m); 100 p:=mintree; 101 if cross(p2,p,p1)>=0 then exit; 102 work(p1,p); 103 work(p,p2); 104 end; 105 106 begin 107 readln(n,m); 108 for i:=1 to m do 109 begin 110 readln(e[i].x,e[i].y,e[i].a,e[i].b); 111 inc(e[i].x); 112 inc(e[i].y); 113 e[i].w:=e[i].a; 114 end; 115 ans.x:=1000000007; 116 ans.y:=1000000007; 117 sort(1,m); 118 p1:=mintree; 119 for i:=1 to m do 120 e[i].w:=e[i].b; 121 sort(1,m); 122 p2:=mintree; 123 work(p1,p2); 124 writeln(ans.x,' ',ans.y); 125 end.