【XSY2501】Mountainous landscape(线段树二分,凸包)

12 篇文章 0 订阅
4 篇文章 0 订阅

先考虑如何确定对于某个 i i i 的答案。

题目的要求是:对于每一个 i = 1 , 2 , ⋯   , n − 1 i=1,2,\cdots,n-1 i=1,2,,n1,找一个最小的 j j j 使得 j > i j>i j>i 且线段 P j P j + 1 P_jP_{j+1} PjPj+1(含端点)与将射线 P i P i + 1 P_iP_{i+1} PiPi+1 略向上平移后所得的射线相交。

这个要求可以转化为:拟一条射线 P i P i + 1 P_iP_{i+1} PiPi+1,找到最小的 j j j 使得 P j P_j Pj 在这条射线上方(不含射线),那么 P j − 1 P j P_{j-1}P_j Pj1Pj 就是我们要找的答案。

在这里插入图片描述

原因也很简单,由于 j j j 是最小的,所以对于任意的 k ∈ [ i + 1 , j − 1 ] k\in [i+1,j-1] k[i+1,j1],都有 P k P_{k} Pk 在这条射线下方(含射线),于是就能保证射线穿过线段 P j − 1 P j P_{j-1}P_j Pj1Pj,在 P j − 1 P j P_{j-1}P_j Pj1Pj 之前不存在射线能穿过的线段。

那么现在问题就变成了:对于每一个 i = 1 , 2 , ⋯   , n − 1 i=1,2,\cdots,n-1 i=1,2,,n1,找一个最小的 j j j 使得 j > i + 1 j>i+1 j>i+1 且点 P j P_j Pj P i P i + 1 P_iP_{i+1} PiPi+1 上方(不含射线,下同)。

考虑二分,判断是否存在一个 j ≤ m i d j\leq mid jmid 满足条件,那么就需要判断点集 { P i + 2 , P i + 3 , ⋯   , P j } \{P_{i+2},P_{i+3},\cdots,P_j\} {Pi+2,Pi+3,,Pj} 中是否存在点在射线上方。

看似我们并没有把问题简单化,甚至更加复杂化,因为貌似我们还是要枚举所有的点,甚至还加上了个二分。

但实际上我们能利用一个很好的性质:把二分的判断转化为判断点集 { P i + 2 , P i + 3 , ⋯   , P j } \{P_{i+2},P_{i+3},\cdots,P_j\} {Pi+2,Pi+3,,Pj} 的上凸壳中是否存在点在射线上方,我们就能通过三分来 O ( log ⁡ n ) O(\log n) O(logn) 判断了。

而且一段区间的点的上凸壳是不会随着询问改变而改变的,而且我们可以通过线段树来维护一段区间的点的上凸壳。

于是我们可以直接在线段树上二分:假设我们当前要在区间 [ l , r ] [l,r] [l,r] 寻找最小的 j j j,那我们用三分判断左儿子内有没有符合条件的 j j j,有的话就去左儿子找,否则去右儿子找。

总时间复杂度 O ( T n log ⁡ 2 n ) O(Tn\log ^2n) O(Tnlog2n)

#include<bits/stdc++.h>

#define N 100010
#define ll long long

using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

struct Point
{
	int x,y;
	Point(){};
	Point(int xx,int yy){x=xx,y=yy;}
}p[N],sta[N],s,t;

Point operator - (Point a,Point b){return Point(a.x-b.x,a.y-b.y);}
ll cross(Point a,Point b){return 1ll*a.x*b.y-1ll*b.x*a.y;}

int n;
int top;

vector<Point>v[N<<2];

void insert(Point u)
{
	while(top>1&&cross(sta[top]-sta[top-1],u-sta[top-1])>=0) top--;
	sta[++top]=u;
}

void merge(int k)
{
	top=0;
	int lc=k<<1,rc=k<<1|1;
	int l=0,r=0;
	while(l<v[lc].size()&&r<v[rc].size())
	{
		if(v[lc][l].x<v[rc][r].x) insert(v[lc][l]),l++;
		else insert(v[rc][r]),r++;
	}
	while(l<v[lc].size()) insert(v[lc][l]),l++;
	while(r<v[rc].size()) insert(v[rc][r]),r++;
	for(int i=1;i<=top;i++) v[k].push_back(sta[i]);
}

void build(int k,int l,int r)
{
	v[k].clear();
	if(l==r)
	{
		v[k].push_back(p[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	merge(k);
}

bool check(int k)
{
	int l=0,r=v[k].size()-1,ans=-1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(!mid||cross(t-s,v[k][mid-1]-s)<cross(t-s,v[k][mid]-s)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	return cross(t-s,v[k][ans]-s)>0;
}

int query(int k,int l,int r,int x)
{
	if(x<=l)
	{
		if(!check(k)) return 0;
		if(l==r) return l-1;
	}
	int mid=(l+r)>>1;
	if(x<=mid)
	{
		int tmp=query(k<<1,l,mid,x);
		if(tmp) return tmp;
	}
	return query(k<<1|1,mid+1,r,x);
}

int main()
{
	int T=read();
	while(T--)
	{
		n=read();
		for(int i=1;i<=n;i++)
			p[i].x=read(),p[i].y=read();
		build(1,1,n);
		for(int i=1;i<n-1;i++)
		{
			s=p[i],t=p[i+1];
			printf("%d ",query(1,1,n,i+2));
		}
		puts("0");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,你遇到的问题是在发送HTTP POST请求时收到了403 Forbidden的错误。这个错误通常表示你没有权限访问所请求的资源。 要解决这个问题,你可以采取以下步骤: 1. 首先,确保你的请求URL正确,并且你有权限访问该URL。你可以尝试在浏览器中直接访问该URL,看看是否能够成功访问。 2. 如果你确定URL是正确的,并且你有权限访问,那么可能是你的请求中缺少了必要的身份验证信息。你可以检查你的请求头中是否含了正确的身份验证信息,比如Token或用户名密码。 3. 另外,你还可以检查服务器端的配置,确保你的请求被正确地处理和授权。你可以查看服务器的日志,以了解更多关于403错误的详细信息。 综上所述,当你收到403 Forbidden错误时,你应该首先检查URL和权限,然后确保请求中含了正确的身份验证信息。如果问题仍然存在,你可以进一步检查服务器端的配置和日志,以找出问题的根本原因。 #### 引用[.reference_title] - *1* [kubeadm init报错10248...(The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ failed)](https://blog.csdn.net/weixin_45969972/article/details/123529966)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST)](https://blog.csdn.net/xsy29000/article/details/103181267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值