【bzoj1007】 [HNOI2008]水平可见直线

noipday1崩了

我打算在一试之前刷至少一百道bzoj

不说废话,来题解

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
 
我们要通过边维护一个上凸壳
把所有边从小到大排序,维护一个单调栈
把边一个一个压入栈,如果栈顶边和它的上一条边的交点在上一条边和新边的交点的右边
那么可以将栈顶元素弹出,画一下图就好了
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
const int N=100001;
const double eps=1e-6;
struct line{double a,b;int pos;
} a[N],s[N];
int n,top,ans[N];
il bool cmp(line a,line b){
    if(fabs(a.a-b.a)>eps) return a.a<b.a;
    return a.b>b.b;
}
il double inter(line a,line b){
    return (b.b-a.b)/(a.a-b.a);
}                        
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&a[i].a,&a[i].b),a[i].pos=i;;
    sort(a+1,a+n+1,cmp);
    a[0].a=500000;
    for(int i=1;i<=n;i++){
        if(fabs(a[i].a-a[i-1].a)<eps) continue;
        while(top>1){
        //    cout<<inter(a[i],s[top-1])<<" "<<inter(s[top-1],s[top])<<endl;
            if(inter(a[i],s[top-1])<=inter(s[top-1],s[top])) top--;
            else break;
        }
        s[++top]=a[i];
    }
    for(int i=1;i<=top;i++) 
        ans[s[i].pos]=true;
    for(int i=1;i<=n;i++){
        if(ans[i]) printf("%d ",i);
    }
    return 0;
}

 

posted @ 2016-11-19 20:43  ExiledPoet  阅读(211)  评论(0编辑  收藏  举报