山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 1007 [HNOI2008]水平可见直线(单调栈)

 

1007: [HNOI2008]水平可见直线

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 5120  Solved: 1899
[Submit][Status][Discuss]

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

HINT

Source

 

【思路】

       单调栈维护下凸包。

 

【代码】

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 6 using namespace std;
 7 
 8 const int N = 50000+10;
 9 const double eps = 1e-8;
10 
11 struct Line {
12     double a,b; int r;
13     bool operator < (const Line& rhs) const {
14         if(fabs(a-rhs.a)<eps) return b<rhs.b;
15         else return a<rhs.a;
16     }
17 }L[N],S[N];
18 
19 double cross(Line x1,Line x2) {
20     return (x2.b-x1.b)/(x1.a-x2.a);
21 }
22 
23 int n,flag[N],top;
24 
25 int main() {
26     scanf("%d",&n);
27     FOR(i,1,n) {
28         scanf("%lf%lf",&L[i].a,&L[i].b);
29         L[i].r=i;
30     }
31     sort(L+1,L+n+1);
32     FOR(i,1,n) {
33         while(top) {
34             if(fabs(S[top].a-L[i].a)<eps) top--;
35             else if(top>1 && cross(L[i],S[top-1])<=cross(S[top],S[top-1])) top--;
36             else break;
37         }
38         S[++top]=L[i];
39     }
40     FOR(i,1,top) flag[S[i].r]=1;
41     FOR(i,1,n) if(flag[i])
42         printf("%d ",i);
43     return 0;
44 }

 

posted on 2016-02-02 09:10  hahalidaxin  阅读(291)  评论(0编辑  收藏  举报