码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ1007】【HNOI2008】水平可见直线 几何 单调栈

时间:2018-03-05 19:35:56      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:code   题目   水平可见直线   scan   cstring   body   can   不可   排序   

题目大意

  给你\(n\)条直线\(y=kx+b\),问你从\(y\)值为正无穷大处往下看能看到那些直线。

  \(1\leq n\leq 500000\)

题解

  如果对于两条直线\(l_i,l_j\)\(k_i=k_j\)\(b_i>b_j\),那么\(l_j\)不可能被看见。

  把直线按\(k\)从小到大排序。如果发生了下图的情况(即\(l_1\)\(l_3\)的交点的\(x\)坐标比\(l_2\)\(l_3\)的交点的\(x\)坐标小),则\(l_2\)就不可能被看见。我们可以用栈来维护当前可以看见的直线,如果栈顶那条直线不满足要求,就pop。

  时间复杂度:每个点只会入栈一次,出栈一次,所以时间复杂度是\(O(n)\)的。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
struct line
{
    double k,b;
    int id;
};
line a[500010];
line b[500010];
int cmp(line a,line b)
{
    if(a.k!=b.k)
        return a.k<b.k;
    return a.b<b.b;
}
int q[500010];
int c[500010];
double cross(line a,line b)
{
    return (b.b-a.b)/(a.k-b.k);
}
int main()
{
    int n;
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++)
    {
        scanf("%lf%lf",&a[i].k,&a[i].b);
        a[i].id=i;
    }
    sort(a+1,a+n+1,cmp);
    int m=0;
    for(i=1;i<=n;i++)
        if(i==n||a[i].k!=a[i+1].k)
            b[++m]=a[i];
    int t=0;
    for(i=1;i<=m;i++)
    {
        while(t>=2&&cross(b[i],b[q[t-1]])<=cross(b[q[t]],b[q[t-1]])+1e-9)
            t--;
        q[++t]=i;
    }
    for(i=1;i<=t;i++)
        c[i]=b[q[i]].id;
    sort(c+1,c+t+1);
    for(i=1;i<=t;i++)
        printf("%d ",c[i]);
    return 0;
}

【BZOJ1007】【HNOI2008】水平可见直线 几何 单调栈

标签:code   题目   水平可见直线   scan   cstring   body   can   不可   排序   

原文地址:https://www.cnblogs.com/ywwyww/p/8510701.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!