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]);
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12968331.html