【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
-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; }
蜉蝣渴望着飞翔,尽管黄昏将至