luogu P3194 [HNOI2008]水平可见直线 |单调栈
题目描述
在 \(x-y\) 直角坐标平面上有 \(n\) 条直线 \(L_1,L_2,…L_n\),若在 \(y\) 值为正无穷大处往下看,能见到 \(L_i\) 的某个子线段,则称 \(L_i\) 为可见的,否则 \(L_i\) 为被覆盖的。 例如,对于直线: \(L_1:y=x\); \(L_2:y=-x\); \(L_3:y=0\); 则 \(L_1\) 和 \(L_2\) 是可见的,\(L_3\) 是被覆盖的。给出 \(n\) 条直线,表示成 \(y=Ax+B\) 的形式(\(|A|,|B| \le 500000\)),且 \(n\) 条直线两两不重合,求出所有可见的直线。
输入格式
第一行为 \(N\) (\(0<N<50000\)),接下来的 \(N\) 行输入 \(A_i,B_i\)
输出格式
从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e4+10;
#define int long long
#define db double
inline void read(int&x){
x = 0;char c;int sign = 1;
do{ c = getchar(); if(c == '-') sign = -1; }while(c < '0' || c>'9');
do{ x = x*10 + c -'0';c = getchar(); }while(c <= '9' && c >= '0');
x *= sign;
}
struct node{
int A,B,id;
}e[N];
const bool cmp(node t1,node t2){
return (t1.A^t2.A) ? t1.A<t2.A : t1.B>t2.B ;
}
inline db sol(int i,int j){return (db)(e[i].B-e[j].B)/(db)(e[j].A-e[i].A);}
int n,st[N],ans[N],top;
signed main(){
read(n);
for(int i=1;i<=n;i++)read(e[i].A),read(e[i].B),e[i].id=i;
sort(e+1,e+1+n,cmp);
for(int i=1;i<=n;i++){
if(e[i].A==e[i-1].A&&i!=1)continue;
while(top>1&&sol(st[top],i)<=sol(st[top],st[top-1]))top--;
st[++top]=i;
ans[top]=e[i].id;
}
sort(ans+1,ans+1+top);
for(int i=1;i<=top;i++)printf("%lld ",ans[i]);
}
不以物喜,不以己悲