• bzoj2395


    分组赛时学到的最小乘积生成树模型,感觉这个思路非常神,可以说是数形结合的经典问题

    由于生成树有两个权值,我们把每个生成树的权值表示成点坐标(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.
    View Code
  • 相关阅读:
    PHP应用目录结构设计
    php 项目性能优化
    Zend Framework的PHP编码规范【1】
    php 如何做在线人数统计
    linux 文件权限
    总结:常用的通用数据处理指令
    全排列(含递归和非递归的解法)
    局部变量,静态局部变量,全局变量,静态全局变量在内存中的存放区别(转)
    C++中引用详解
    Pascal三角形
  • 原文地址:https://www.cnblogs.com/phile/p/4573200.html
Copyright © 2020-2023  润新知