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
-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.