[HNOI2008]水平可见直线

VI.[HNOI2008]水平可见直线

一开始以为这是半平面交模板;后来一想,直接求出凸包来就行了。

我们仍然将所有直线按照斜率从小到大排序。不过这时,我们只需要使用单调栈维护即可。

具体而言,设栈顶次位、首位直线分别为y=k1x+b1,y=k2x+b2

则其交点位于

(b1b2k2k1,k2(b1b2k2k1)+b2)

假设我们现在插入一条新直线y=k0x+b0,则弹出队尾,当且仅当

k2(b1b2k2k1)+b2k0(b1b2k2k1)+b0

因为其分别是首位、次位直线,所以必有k2k1>0,所以两边直接乘上k2k1,最终得到判别式

k2(b1b2)+b2(k2k1)k0(b1b2)+b0(k2k1)

直接应用即可。

时间复杂度O(nlogn)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,k[50100],b[50100],ord[50100],s[50100],tp;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d%d",&k[i],&b[i]),ord[i]=i;
	sort(ord+1,ord+n+1,[](int u,int v){return k[u]==k[v]?b[u]>b[v]:k[u]<k[v];});
	s[tp=1]=ord[1];
	for(int i=2;i<=n;i++){
		if(k[ord[i]]==k[ord[i-1]])continue;
		while(tp>=2&&1ll*k[s[tp]]*(b[s[tp-1]]-b[s[tp]])+1ll*b[s[tp]]*(k[s[tp]]-k[s[tp-1]])<=1ll*k[ord[i]]*(b[s[tp-1]]-b[s[tp]])+1ll*b[ord[i]]*(k[s[tp]]-k[s[tp-1]]))tp--;
		s[++tp]=ord[i];
	}
	sort(s+1,s+tp+1);
	for(int i=1;i<=tp;i++)printf("%d ",s[i]);puts("");
	return 0;
} 

posted @   Troverld  阅读(47)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示