hdu.Taxi

在这里插入图片描述
题意 :

  • 每次询问给一个坐标(x,y),求它到n个点的值的最大值,值是曼哈顿距离和点的权值中的较小值

思路 :

  • 一个点到n个点的曼哈顿距离的最大值和最小值是经典模型:
    max ⁡ ( ∣ x − x i ∣ + ∣ y − y i ∣ ) \max(|x-x_i|+|y-y_i|) max(xxi+yyi)
    = max ⁡ ( x + y − x i − y i , x − y − x i + y 1 , − x + y + x i − y i , − x − y + x i + y i ) =\max(x+y-x_i-y_i,x-y-x_i+y_1,-x+y+x_i-y_i,-x-y+x_i+y_i) =max(x+yxiyi,xyxi+y1,x+y+xiyi,xy+xi+yi)
    因此,只需要求出 x i + y i x_i+y_i xi+yi x i − y i x_i-y_i xiyi的最大值和最小值,即可O(1)得到曼哈顿距离的最大值
  • 二分答案,判断答案是否大于等于mid,对权值进行排序,我们通过第二个二分找到第一个权值大于等于mid的点,这样的话,编号小于这个点的值不可能大于等于mid(因为值是取两者的较小值),而编号大于等于这个点的权值都大于等于mid了,现在就要看编号大于等于这个点的曼哈顿距离是否都大于等于mid,求这些点的曼哈顿距离的最大值可以一开始预处理,这里就可以O(1)取max了
#include <iostream>
#include <algorithm>
#define endl '\n'
#define _(a) cout << #a << ": " << (a) << "    "
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;

struct node {
    ll x, y, w;
    bool operator < (const node&xx) const {
        return w < xx.w;
    }
}a[N];
int n, q;
int qx, qy;
ll mx1[N], mx2[N], mi1[N], mi2[N];

bool check (ll mid) {
    int l = 0, r = n + 1;
    while (l + 1 != r) {
        int Mid = (l + r) >> 1;
        if (a[Mid].w >= mid) r = Mid;
        else l = Mid;
    }
    if (r > n || a[r].w < mid) return false;
    ll mx = max(max(qx + qy - mi1[r], qx - qy - mi2[r]), max(qy - qx + mx2[r], -(qx + qy) +mx1[r]));
    return (mx >= mid);
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int _; cin >> _;
    while (_ -- ) {
        cin >> n >> q;
        for (int i = 1; i <= n; ++ i) {
            cin >> a[i].x >> a[i].y >> a[i].w;
        }
        sort(a + 1, a + n + 1);
        mx1[n] = mi1[n] = a[n].x + a[n].y;
        mx2[n] = mi2[n] = a[n].x - a[n].y;
        for (int i = n - 1; i; -- i) {
            mx1[i] = max(mx1[i + 1], a[i].x + a[i].y);
            mx2[i] = max(mx2[i + 1], a[i].x - a[i].y);
            mi1[i] = min(mi1[i + 1], a[i].x + a[i].y);
            mi2[i] = min(mi2[i + 1], a[i].x - a[i].y);
        }
        while (q -- ) {
            cin >> qx >> qy;
            ll l = -1, r = 2e9 + 1;
            while (l + 1 != r) {
                ll mid = (l + r) >> 1;
                if (check(mid)) l = mid;
                else r = mid;
            }
            cout << l << endl;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值