[BZOJ1007][HNOI2008]水平可见直线(单调栈+计算几何)

题目描述

传送门

题解

由题意可知能看见的直线一定呈下凸。
以k为第一关键字,b为第二关键字排序,得到斜率不降、斜率相等时截距不降的直线序列。维护自底向上斜率单增的单调栈,当直线q[r-1]和当前枚举到的直线i共同将q[r]的最大值覆盖或者枚举到的i和q[r]平行时将q[r]弹出,最后在栈内的直线即为可以看到的直线。

代码

#include<algorithm> 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
const int max_n=5e4+5;

int n,l,r,cnt,q[max_n],ans[max_n];
struct hp{int k,b,id;}a[max_n];

inline int cmp(hp a,hp b)
{
    return a.k<b.k||(a.k==b.k&&a.b<b.b);
}
inline bool check(int x1,int x2,int x3)
{
    LL w1=(LL)(a[x1].k-a[x3].k)*(LL)(a[x2].b-a[x1].b);
    LL w2=(LL)(a[x1].k-a[x2].k)*(LL)(a[x3].b-a[x1].b);
    return w1>=w2;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        scanf("%d%d",&a[i].k,&a[i].b),a[i].id=i;
    sort(a+1,a+n+1,cmp);
    l=r=0;
    q[++r]=1;
    for (int i=2;i<=n;++i)
    {
        while (l<r-1&&check(i,q[r-1],q[r])) r--;
        while (l<r&&a[q[r]].k==a[i].k) r--;
        q[++r]=i;
    }
    for (int i=l+1;i<=r;++i)
        ans[++cnt]=a[q[i]].id;
    sort(ans+1,ans+cnt+1);
    for (int i=1;i<=cnt;++i)
        printf("%d ",ans[i]);
}

你可能感兴趣的:(单调栈,计算几何,bzoj,hnoi)