【BZOJ】1007 [HNOI2008]水平可见直线 半平面交(单调栈)

本文介绍了一种解决半平面交问题的方法——单调栈。通过将所有一次函数按斜率降序排序,利用单调栈来维护函数的可见部分,解决了半平面交的问题。最后给出了AC代码。

题目传送门

半平面交这个名字好可怕啊……但是其实就是一个单调栈。

我们把所有的一次函数按斜率降序排序,设 i 为当前函数的编号,sk[]为单调栈, top 为栈顶指针。定义 calc(x,y) 函数为计算两个一次函数的交点的横坐标。

如果 calc(i,sk[top])>=calc(sk[top],sk[top1]) ,即下图的情况:

这里写图片描述

如果1号点在2号点的右边,显然 sk[top] 这条函数被 sk[top1] i 这两条函数覆盖,变得不可见,并且对以后的维护也没有了贡献,直接弹出即可。

然后这题就变成了单调栈的水题,直接维护即可。

附上AC代码:

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;

const int N=5e4+10;
struct note{
    int k,b,wz;
    bool operator < (const note lyf) const {return k==lyf.k?b>lyf.b:k>lyf.k;}
}a[N];
int n,sk[N],ans[N],top;

inline char nc(void){
    static char ch[100010],*p1=ch,*p2=ch;
    return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &a){
    static char c=nc();int f=1;
    for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
    for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());
    return (void)(a*=f);
}

inline double calc(int i,int j) {return (a[i].b-a[j].b)*1.0/(double)(a[j].k-a[i].k);}

int main(void){
    freopen("x.txt","r",stdin);
    read(n);
    for (int i=1; i<=n; ++i) read(a[i].k),read(a[i].b),a[i].wz=i;
    sort(a+1,a+1+n);
    for (int i=1; i<=n; ++i){
        if (a[i].k==a[i-1].k&&i>1) continue;
        while (top>1&&calc(sk[top],i)>=calc(sk[top-1],sk[top])) --top;
        sk[++top]=i,ans[top]=a[i].wz;
    }
    sort(ans+1,ans+1+top);
    for (int i=1; i<=top; ++i) printf("%d ",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值