bzoj1007[HNOI2008]水平可见直线

cycleke神说要用半平面交(其实他也用的凸包),把我吓了一跳,后来发现(看题解)其实可以先按斜率排序,再将最小的两条线入栈,如果其与栈顶元素的交点在上一个点的左边,则将栈顶元素出栈。这是一个开口向上的半凸包。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define eps 1e-8
using namespace std;
struct node{
    double a,b;
    int xu;
}e[100005],st[100005];
int cnt,n,ans[100005];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool cmp(node a,node b)
{
    if (fabs(a.a-b.a)<eps) return a.b<b.b;
    else return a.a<b.a;
}
double xl(node a,node b)
{
    return (b.b-a.b)/(a.a-b.a);
}
void insert(node a)
{
    while (cnt)
    {
        if(fabs(st[cnt].a-a.a)<eps)cnt--;
        else if(cnt>1&&xl(a,st[cnt-1])<=xl(st[cnt],st[cnt-1]))
            cnt--;
        else break;
    }
    st[++cnt]=a;
}
void solve()
{
    for (int i=1;i<=n;i++) insert(e[i]);
    for (int i=1;i<=cnt;i++) ans[st[i].xu]=1;
    for (int i=1;i<=n;i++) if (ans[i]) printf("%d ",i); 
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        e[i].a=read(),e[i].b=read();
        e[i].xu=i;
    }
    sort(e+1,e+1+n,cmp);
    solve();
}

代码速度感人,将就看吧

posted @ 2016-11-04 08:29  chenhaowen  阅读(106)  评论(0编辑  收藏  举报