BZOJ 1007: [HNOI2008]水平可见直线 平面直线
1007: [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
HINT
题解:
当前直线与相对他斜率次大和次次大的2条直线时,如果与次大的(或者次次大)的交点在次大与次次大的交点左边,那么次大的直线一定被覆盖掉了!
画图自己看!(其实也就是这三个点形成一个凸包,然后上凸包的边所在直线一定看得到,下凸包一定被覆盖!)
代码
#include<bits/stdc++.h> using namespace std; const int N = 2e5+10, M = 30005, mod = 1e9 + 7, inf = 0x3f3f3f3f; typedef long long ll; #define eps 1e-8 struct line{double a,b;int index;}l[N],seg[N]; bool bo[N]; int top = 0, n ; int cmp (line x,line y) { if(fabs(x.a-y.a)<=eps) return x.b<y.b; return x.a<y.a; } double crossx(line x,line y) { return (y.b-x.b) / (x.a-y.a); } void inserts(line x) { while(top) { if(fabs(seg[top].a - x.a)<=eps) top--; else if(top>1&&crossx(x,seg[top-1])<=crossx(seg[top],seg[top-1])) top--; else break; } seg[++top] = x; } void solve() { sort(l+1,l+n+1,cmp); for(int i=1;i<=n;i++) inserts(l[i]); for(int i=1;i<=top;i++) bo[seg[i].index] = true; for(int i=1;i<=n;i++) if(bo[i]) printf("%d ",i); printf("\n"); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&l[i].a,&l[i].b); l[i].index = i; } solve(); }