[bzoj1007]:[HNOI2008]水平可见直线(单调栈)

来源:互联网 发布:单片机识别条形码 编辑:程序博客网 时间:2024/05/29 18:23

传送门
姑且算是计算几何第一题吧。。
首先,最后的图形一定是一个凸包形状的东西。
所以,我们按照k递增为第一关键字,b递减为第二关键字,排个序。
然后我们就可以维护一个单调栈,处理结果了。
方法:
我们设当前直线与栈顶直线的交点为x1,栈顶直线与栈顶第二条直线的交点为x2
如果x1<=x2,那么弹出栈顶;否则将当前直线压入栈中。
原理可以看这个图,直到看懂为止。
这里写图片描述
懂了的话,那就没什么了。
对了,目前洛谷Rank1
代码:

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<cstdlib>#define ll long longusing namespace std;inline int read(){    int x=0;char ch=' ';int f=1;    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();    if(ch=='-')f=-1,ch=getchar();    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();    return x*f;}const int N=5e5+5;const double eps=1e-8;struct line{    double k,b;    int id;    inline bool operator < (const line& y) const {        if(fabs(k-y.k)<eps)return b>y.b;        return k<y.k;    }}a[N];int n,top,vis[N],s[N];inline double calc(const line& a,const line& b){    return (b.b-a.b)/(a.k-b.k);}int main(){    n=read();    for(int i=1;i<=n;i++)scanf("%lf %lf",&a[i].k,&a[i].b),a[i].id=i;    sort(a+1,a+n+1);    top=1;s[1]=1;    for(int i=2;i<=n;i++){        if(fabs(a[i].k-a[i-1].k)<eps)continue;        while(top>1&&calc(a[i],a[s[top]])<=calc(a[s[top]],a[s[top-1]])+eps)top--;        s[++top]=i;    }    for(int i=1;i<=top;i++)vis[a[s[i]].id]=1;    for(int i=1;i<=n;i++)if(vis[i])printf("%d ",i);    return 0;}
阅读全文
0 0