• bzoj1007[HNOI2008]水平可见直线


    Description

    在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.
    例如,对于直线:
    L1:y=x; L2:y=-x; L3:y=0
    则L1和L2是可见的,L3是被覆盖的.
    给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.

    Input

      第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

    Output

      从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

    Sample Input

    3
    -1 0
    1 0
    0 0

    Sample Output

    1 2

     

    可以发现最后就是一个下凸的形状。首先按照斜率排序,按顺序加入,维护一个单调栈,每次加入时检查栈顶元素,画图可以发现,如果当前加入的直线与栈顶直线交点在前一个交点的左边,则栈顶元素出栈。这样就是O(n)了。

     1 program lines(input,output);
     2 var
     3   a,b,c,z:array[0..50050]of longint;
     4   d:array[0..50050]of double;
     5   ans:array[0..50050]of boolean;
     6   n,m,i,j:longint;
     7 procedure sort(q,h:longint);
     8 var
     9   i,j,xa,xb,t:longint;
    10 begin
    11    i:=q;j:=h;xa:=a[(i+j)>>1];xb:=b[(i+j)>>1];
    12    repeat
    13      while (a[i]<xa) or (a[i]=xa) and (b[i]>xb) do inc(i);
    14      while (xa<a[j]) or (xa=a[j]) and (xb>b[j]) do dec(j);
    15      if i<=j then
    16         begin
    17            t:=a[i];a[i]:=a[j];a[j]:=t;
    18            t:=b[i];b[i]:=b[j];b[j]:=t;
    19            t:=c[i];c[i]:=c[j];c[j]:=t;
    20            inc(i);dec(j);
    21         end;
    22    until i>j;
    23    if j>q then sort(q,j);
    24    if i<h then sort(i,h);
    25 end;
    26 function claris(x,y:longint):double;
    27 begin
    28    exit((b[y]-b[x])/(a[x]-a[y]));
    29 end;
    30 begin
    31    assign(input,'lines.in');assign(output,'lines.out');reset(input);rewrite(output);
    32    readln(n);
    33    for i:=1 to n do begin readln(a[i],b[i]);c[i]:=i; end;
    34    sort(1,n);
    35    m:=1;
    36    for i:=2 to n do if a[i]<>a[i-1] then begin inc(m);a[m]:=a[i];b[m]:=b[i];c[m]:=c[i] end;
    37    z[1]:=1;z[2]:=2;d[2]:=claris(1,2);j:=2;
    38    for i:=3 to m do
    39       begin
    40          while (claris(i,z[j])<=d[j]) and (j>1) do dec(j);
    41          inc(j);z[j]:=i;d[j]:=claris(z[j],z[j-1]);
    42       end;
    43    fillchar(ans,sizeof(ans),false);
    44    for i:=1 to j do ans[c[z[i]]]:=true;
    45    for i:=1 to n do if ans[i] then write(i,' ');
    46    close(input);close(output);
    47 end.
  • 相关阅读:
    Lucas 定理
    C语言II博客作业04
    C语言II博客作业03
    C语言II博客作业02
    C语言II博客作业01
    学期总结
    First project
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
  • 原文地址:https://www.cnblogs.com/Currier/p/6504703.html
Copyright © 2020-2023  润新知