CodeForces - 491B New York Hotel(数学)

这篇博客讨论了一道算法竞赛题目,涉及到二维平面上的点集和距离查询。作者通过分析得出,可以将每个点的位置转换为四个象限的坐标表示,然后维护每个象限的最大坐标值,从而在O(1)的时间复杂度内回答每个查询。代码中使用了KDtree但超时,最终采用优化后的线性时间复杂度解决方案。

题目链接:点击查看

题目大意:给出一个大小为 r * c 的二维平面,再给出 n 个点,接下来有 m 次询问,没出询问会给出一个点 ( x , y ) ,需要计算出 ans[ i ] 为距离点 ( x , y ) 最远的那个点的距离,现在要求求出最小的那个 ans[ i ] 的值,并且输出其下标

题目分析:读完题想用 KDtree,去网上找了个模板套上发现会 T,然后就只能中规中矩去推公式了

假设以某个询问点 ( x , y ) 为原点来说,对于任意一点 ( a , b ) 与其距离分为四种情况讨论:

  1. 位于第一象限:a - x + b - y
  2. 位于第二象限:x - a + b - y
  3. 位于第三象限:x - a + y - b
  4. 位于第四象限:a - x + y - b

所以对于某个询问 ( x , y ) 来说,我们只需要将其分为四个象限,然后分别统计答案维护最大值即可

但是乍一看并没有在时间复杂度上进行优化,因为整体算法还是 O( n * n ) 的,而题目中只需要找到 “平面最远点对” 即可,所以将上面四种情况移一下项:

  1. 位于第一象限:(a + b)+(-x - y)
  2. 位于第二象限:(-a + b)+(x - y)
  3. 位于第三象限:(-a - b)+(x + y)
  4. 位于第四象限:(a - b)+(-x + y)

换句话说,对于某次询问的 ( x , y ) 来说,因为将所有的距离拆分成两个式子的加和,显然最远距离肯定是前一项的最大值,所以对于前面 n 个点来说,分别维护一下前面括号中内容的最大值,这样就能 O( 1 ) 去询问最大点对的距离了

代码:
 

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
     
typedef long long LL;
     
typedef unsigned long long ull;
     
const int inf=0x3f3f3f3f;

const int N=1e5+100;

vector<int>node[4];

int mmax[4];

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,m;
	scanf("%d%d",&n,&m);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		node[0].push_back(x+y);
		node[1].push_back(x-y);
		node[2].push_back(y-x);
		node[3].push_back(-x-y);
	}
	for(int i=0;i<4;i++)
		mmax[i]=*max_element(node[i].begin(),node[i].end());
	scanf("%d",&n);
	int ans=2e9,mark=-1;
	for(int i=1;i<=n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		int res=0;
		res=max(res,mmax[0]-x-y);
		res=max(res,mmax[1]-x+y);
		res=max(res,mmax[2]-y+x);
		res=max(res,mmax[3]+x+y);
		if(res<ans)
		{
			ans=res;
			mark=i;
		}
	}
	printf("%d\n%d\n",ans,mark);





    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值