[好题][曼哈顿距离][二分]Taxi 2022杭电多校第3场 1011

23 篇文章 0 订阅

There are nn towns in Byteland, labeled by 1,2,\dots,n1,2,…,n. The ii-th town's location is (x_i,y_i)(xi​,yi​). Little Q got a taxi VIP card, he can use the VIP card to cut down the taxi fare. Formally, assume Little Q is at (x',y')(x′,y′), if he calls a taxi to drive him to the kk-th town, the VIP card will reduce \min(|x'-x_k|+|y'-y_k|,w_k)min(∣x′−xk​∣+∣y′−yk​∣,wk​) dollars.

Little Q wants to make full use of his VIP card. He will give you qq queries, in each query you will be given his location, and you need to choose a town such that the VIP card will reduce the most taxi fare.

Input

The first line contains a single integer TT (1 \leq T \leq 1001≤T≤100), the number of test cases. For each test case:

The first line contains two integers nn and qq (1 \leq n,q \leq 100\,0001≤n,q≤100000), denoting the number of towns and the number of queries.

Each of the following nn lines contains three integers x_ixi​, y_iyi​ and w_iwi​ (1 \leq x_i,y_i,w_i \leq 10^91≤xi​,yi​,wi​≤109), describing a town.

Each of the following qq lines contains two integers x'x′ and y'y′ (1 \leq x',y' \leq 10^91≤x′,y′≤109), describing a query.

It is guaranteed that the sum of all nn is at most 500\,000500000, and the sum of all qq is at most 500\,000500000.

Output

For each query, print a single line containing an integer, denoting the maximum possible reduced taxi fare.

Sample

InputOutput
 
1 3 4 1 5 7 5 1 6 2 3 9 1 5 2 2 4 3 10 10
 
6 4 5 9

题意: 在一个二维平面上有n个点,每个点还具有一个点权wi,q次询问,每次询问给出一个点(x, y),该点到各点的代价为min(两点间曼哈顿距离, wi),求该点到各点代价的最大值。

分析: 在做这道题之前需要知道一个结论,找某点到各点曼哈顿距离最大值只需要看4个点,分别是x+y值最大的点、x-y值最大的点、-x+y值最大的点和-x-y值最大的点,这4点到给定点的曼哈顿距离最大值就是全部点到给定点的曼哈顿距离最大值。设给定点为(x', y'),则证明可以由下图给出:

在知道这个结论后这道题目做起来会稍微简单一些,接下来可以对各点按照权值wi从小到大排序,然后二分点的编号,初始时l = 1,r = n,设dis为[mid, n]中的各点到给定点曼哈顿距离最大值,如果dis >= w[mid],那么[mid, n]中的各点对答案的贡献至少也是w[mid],所以可以用w[mid]更新一下答案,并且可以知道[1, mid-1]中的各点w[i]小于等于w[mid],所以它们不可能再更新答案了,也就不用考虑这些点了,将需要考虑的范围缩小到[mid+1, n],而如果dis < w[mid],那么[mid, n]中的各点对答案的贡献一定是d,所以用d更新一下答案,然后将需要考虑的范围缩小到[1, mid-1]。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;

struct node{
	int x, y, w;
}a[100005];

bool cmp(node x, node y){
	return x.w < y.w;
}

int mx1[100005];//记录后i个点的x+y最大点 
int mx2[100005];//记录后i个点的x-y最大点
int mx3[100005];//记录后i个点的-x+y最大点 
int mx4[100005];//记录后i个点的-x-y最大点 

int dis(int t, int x, int y){//dis(t)返回后t个点中曼哈顿距离最大值 
	int dis1 = abs(a[mx1[t]].x-x)+abs(a[mx1[t]].y-y);
	int dis2 = abs(a[mx2[t]].x-x)+abs(a[mx2[t]].y-y);
	int dis3 = abs(a[mx3[t]].x-x)+abs(a[mx3[t]].y-y);
	int dis4 = abs(a[mx4[t]].x-x)+abs(a[mx4[t]].y-y);
	return max(max(dis1, dis2), max(dis3, dis4));
}

signed main()
{
	int T;
	cin >> T;
	while(T--){
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++)
			scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].w);
		sort(a+1, a+n+1, cmp);
		mx1[n] = mx2[n] = mx3[n] = mx4[n] = n;
		for(int i = n-1; i >= 1; i--){
			if(a[mx1[i+1]].x+a[mx1[i+1]].y < a[i].x+a[i].y)
				mx1[i] = i;
			else 
				mx1[i] = mx1[i+1];
			if(a[mx2[i+1]].x-a[mx2[i+1]].y < a[i].x-a[i].y)
				mx2[i] = i;
			else 
				mx2[i] = mx2[i+1];
			if(-a[mx3[i+1]].x+a[mx3[i+1]].y < -a[i].x+a[i].y)
				mx3[i] = i;
			else 
				mx3[i] = mx3[i+1];
			if(-a[mx4[i+1]].x-a[mx4[i+1]].y < -a[i].x-a[i].y)
				mx4[i] = i;
			else 
				mx4[i] = mx4[i+1];
		}
		for(int i = 1; i <= m; i++){
			int x, y;
			scanf("%d%d", &x, &y);
			int l = 1, r = n, ans = 0;
			while(l <= r){
				int mid = l+r>>1;
				if(dis(mid, x, y) > a[mid].w){
					ans = max(ans, a[mid].w);
					l = mid+1;
				}
				else{
					ans = max(ans, dis(mid, x, y));
					r = mid-1;
				}
			}
			printf("%d\n", ans);
		}
	} 
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值