【BZOJ1007】水平可见直线(单调栈)

【BZOJ1007】水平可见直线(单调栈)

题解

Description

  在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为
可见的,否则Li为被覆盖的.
例如,对于直线:
L1:y=x; L2:y=-x; L3:y=0
则L1和L2是可见的,L3是被覆盖的.
给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.

Input

  第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

  从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3

-1 0

1 0

0 0

Sample Output

1 2

题解

首先,如果斜率相同,显然只需要留下截距大的直线
去掉没有用的直线之后
剩余直线按照斜率从小到大排序
用一个单调栈来维护每条直线
如果当前新加的直线与top的交点在top-1的交点的左侧
证明这条直线可以被完全覆盖
然后就不难了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 55000
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n,tot;
struct Line{int a,b,id;}e[MAX];
bool cmp(Line a,Line b){if(a.a!=b.a)return a.a<b.a;return a.b>b.b;}
double ppp(int x,int y){return 1.0*(e[y].b-e[x].b)/(e[x].a-e[y].a);}
int S[MAX],ans[MAX],top=0;
int main()
{
    n=read();
    for(int i=1;i<=n;++i)e[i].a=read(),e[i].b=read(),e[i].id=i;
    sort(&e[1],&e[n+1],cmp);
    e[0].a=-1e9;
    for(int i=1;i<=n;++i)if(e[i].a!=e[i-1].a)e[++tot]=e[i];
    n=tot;
    S[++top]=1;ans[top]=e[1].id;
    for(int i=2;i<=n;++i)
    {
        while(top>1&&ppp(i,S[top-1])>=ppp(i,S[top]))top--;
        S[++top]=i;ans[top]=e[i].id;
    }
    sort(&ans[1],&ans[top+1]);
    for(int i=1;i<=top;++i)printf("%d ",ans[i]);puts("");
    return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8150441.html

时间: 2024-10-09 18:04:21

【BZOJ1007】水平可见直线(单调栈)的相关文章

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

1007: [HNOI2008]水平可见直线 题目:传送门 题解: 蒟蒻在bzoj上做的第一道计算几何 其实这道题并不难...(所以我A了) 仔细想想不难发现,其实我们只需要维护一个下凸的图形... 只有在这个图形上的直线才不会被覆盖,也就是可以被上帝直线看到的孩子 为什么呢...自己画个图模拟吧. 那么具体的做法我们就要采用单调栈啦! 把给出的直线按照斜率从小到大排序(如果斜率相同的话就按照b来排) 然后一个一个放入我们强大的单调栈中,在加入的同时我们当然还要进行维护: 如果栈顶的直线与新加直

bzoj1007/luogu3194 水平可见直线 (单调栈)

先按斜率从小到大排序,然后如果排在后面的点B和前面的点A的交点是P,那B会把A在P的右半段覆盖掉,A会把B在P的左半段覆盖掉. 然后如果我们现在又进来了一条线,它跟上一条的交点还在上一条和上上条的左边,这就说明上一条完全被覆盖了 这样的话,维护一个单调栈做一做就可以了 (要先处理一下,斜率相同的只留下B最大的,而且会有重合的线,都要输出) 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define ll long l

[BZOJ1007]水平可见直线

发现其实是一个下凸壳,所以先按斜率排序,然后判断当前直线与栈顶直线的交点是否更靠右 注意平行的情况 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define maxn 50005 5 #define esp 1e-8 6 struct node{ 7 double a,b; 8 int id; 9 }V[maxn]; 10 double a[maxn],b[maxn]; 11 int sta[maxn],top; 12 bool

BZOJ1007 水平相交直线

按照斜率排序,我们可以想象如果你能看到大于等于三条直线那么他一定会组成一个下凸包,这样我们只需要判断如果当前这条直线与栈顶第二直线相交点相比于栈顶第二直线与栈顶直线相交点靠左那么他就不满足凸包性质. 画画图想想看. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1000005; 4 double eps=1e-8; 5 bool ans[1000005]; 6 struct node 7 { 8 double k,

BZOJ 1007 HNOI 2008 水平可见直线 计算几何+栈

题目大意:给出一些笛卡尔系中的一些直线,问从(0,+∞)向下看时能看到哪些直线. 思路:半平面交可做,但是显然用不上.类似于求凸包的思想,维护一个栈.先将所有直线按照k值排序,然后挨个压进去,遇到有前一个交点被挡住的话就先弹栈. 比较闹心的是去重.我的方法是压栈之前先去重,然后在处理. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #includ

[HNOI2008] [BZOJ1007] 水平可见直线

Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.    例如,对于直线:    L1:y=x; L2:y=-x; L3:y=0    则L1和L2是可见的,L3是被覆盖的.    给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线. Input 第一行为N(0 < N < 50000),接下来的N行输入A

BZOJ1007|水平可见直线|模拟

Description在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.例如,对于直线:L1:y=x; L2:y=-x; L3:y=0则L1和L2是可见的,L3是被覆盖的.给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.Input第一行为N(0 < N < 50000),接下来的N行输入Ai,BiOutput从小到大输出可见直

【bzoj1007】[HNOI2008]水平可见直线 半平面交/单调栈

题目描述 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.例如,对于直线:L1:y=x; L2:y=-x; L3:y=0则L1和L2是可见的,L3是被覆盖的.给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线. 输入 第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi 输出 从小到大输出可见直线的编号,两两中间

BZOJ_1007_ [HNOI2008]_水平可见直线_(单调栈+凸包)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1007 给出一些直线,沿着y轴从上往下看,能看到多少条直线. 分析 由于直线相交,会遮挡住一些直线. 自己画画图就可以发现,最后能看见的直线,也就是在最上面的那些直线一定构成一个凸包的下凸壳(没错一定是凸的). 接下来就是如何求这个下凸壳了. 先按照斜率为第一关键字,截距为第二关键字,将直线从小到大排序.用一个斜率单调递增的栈来维护凸壳. 我们按照排序后的顺序添加直线,画画图会发现: 1.斜率