P3194 [HNOI2008]水平可见直线 题解

时间:2021-08-04
本文章向大家介绍P3194 [HNOI2008]水平可见直线 题解,主要包括P3194 [HNOI2008]水平可见直线 题解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

光看是解不出题的。

自(he) 己(wan)画(ti)图(jie),发现没被挡住的多条直线会在平面上形成一个下凸包,从左到右斜率递增。

(取自p_b_p_b题解)

于是,我们将直线以斜率为第一关键字,截距为第二关键字从大到小排序;

然后从前往后枚举直线,加入单调栈。

当单调栈内直线数量 \(\ge\) 2时,设 \(l_1\)\(l_2\) 为栈顶两直线,\(L\) 为枚举直线,用一元二次方程算出 \(L\)\(l_1\)\(l_1\)\(l_2\) 的交点横坐标 \(x_1\)\(x_2\) 。若 \(x_2>x_1\) ,则 \(l_1\) 已经被覆盖,退栈,重复该操作到 \(x_2<x_1\)​ 或栈中只剩一条直线。

#include <bits/stdc++.h>
#define ll long long
#define rgi register int
using namespace std;
const int M=5e4+7;
inline int read(){
	int w=0,r=1;char c=getchar();
	while(!(isdigit(c)||c=='0'))c=getchar();
	if(c=='-')r=-1,c=getchar(); 
	while(isdigit(c))w=w*10+c-'0',c=getchar();
	return w*r;
}
int n,m,stk[M],ans[M],cnt;double a,b,r;
struct l{
	int ii;double k,b;
}p[M];
bool cmp(l aa,l bb){
	return aa.k>bb.k||(aa.k==bb.k&&aa.b>bb.b);
}
double xx(int aa,int bb){
	return (double)(p[bb].b-p[aa].b)/(p[aa].k-p[bb].k);
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%lf%lf",&p[i].k,&p[i].b);
		p[i].ii=i;
	}
	sort(p+1,p+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(p[i].k==p[stk[cnt]].k&&i>1)continue; 
		while(cnt>=2&&xx(stk[cnt-1],stk[cnt])<=xx(stk[cnt],i))cnt--;
		stk[++cnt]=i;
		ans[cnt]=p[i].ii;
	}
	sort(ans+1,ans+cnt+1);
	for(int i=1;i<=cnt;i++)printf("%d ",ans[i]);
	printf("\n");
	return 0;
} 
/*
3
-1 0
1 0
0 0
*/

原文地址:https://www.cnblogs.com/wcy2006/p/15100864.html