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.

 

posted @ 2017-03-05 11:28  Klaier  阅读(151)  评论(0编辑  收藏  举报