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

来源:互联网 发布:java extends 源码 编辑:程序博客网 时间:2024/06/07 22:59

题目:

我是超链接

题解:

如何判断两条直线已经被另一条直线覆盖?
令y1=k1x+b1 , y2=k2x+b2 , y3=k3x+b3
求y1与y3的交点横纵坐标
k1x+b1=k3x+b3
x=(b3−b1)/(k1−k3)
y=k1(b3−b1)/(k1−k3)+b1
然后求y2在x处的函数值
y2=k2(b3−b1)/(k1−k3)+b2
若y2≤y
(k1−k3)∗(b2−b1)≤(k1−k2)∗(b3−b1)
那么直线y2已经被y1和y3完全覆盖

这个直线我们可以运用单调栈维护,啊啊啊乘的时候要用longlong啊

再加上一些最优值的维护就进化为单调队列,再把k,b换掉就是斜率优化dp啦

代码:

#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#define LL long longusing namespace std;struct hh{int k,b,id;}l[50005];int stack[50005],ans[50005];int cmp(hh a,hh b){if (a.k==b.k) return a.b<b.b;else return a.k<b.k;}bool fg(int x1,int x2,int x3){return (LL)(l[x2].k-l[x1].k)*(l[x3].b-l[x1].b)<=(LL)(l[x1].k-l[x3].k)*(l[x1].b-l[x2].b);}// l1与l3把l2覆盖 int main(){    int n,i,top=0;    scanf("%d",&n);    for (i=1;i<=n;i++) scanf("%d%d",&l[i].k,&l[i].b),l[i].id=i;    sort(l+1,l+n+1,cmp);    for (i=1;i<=n;i++)    {        while ((top>1 && fg(i,stack[top],stack[top-1])) || (top && l[i].k==l[stack[top]].k)) top--;        stack[++top]=i;    }    while (top)    {        ans[++ans[0]]=l[stack[top]].id;        top--;    }    sort(ans+1,ans+1+ans[0]);    for (i=1;i<=ans[0];i++) printf("%d ",ans[i]);}
阅读全文
1 0
原创粉丝点击