2022“杭电杯”中国大学生算法设计超级联赛(3)-K - Taxi -曼哈顿+二分

K - Taxi

题意

开始给你n个点 每个点的坐标\((x_i,y_i)\),权值\(w_i\),一共q次询问, 每次询问给你一个点(qx, qy),求该点到前面某个点的距离的最大值是多少。
两个点之间的距离定义为\(min(|x - xi| + |y - yi|, wi)\)

思路

我们可以O(1)地求出集合外一点到该集合中的某一个点的最大曼哈顿距离。

\[max(abs(qx - x) + abs(qy - y)) = max(qx-x+qy-y, qx-x+y-qy, x-qx+qy-y, x-qx+y-qy) = max((qx+qy)-(x+y), (x+y)-(qx+qy), (qx-qy)-(x-y), (x-y)-(qx-qy)) = max(|(qx+qy) - (x+y)|, |(qx-qy) - (x-y)|)\]

维护区间的\(mx_x+y, mi_x+y, mx_x-y, mi_x-y\)即可求得区间最大曼哈顿距离

然后我们将点按权值从大到小排
然后二分城市 对于某个点x 比较x及以后的最大曼哈顿距离d,如果d>x.w说明x即以后的区间可以找到比x.w大的更优解, 我们就再向右二分。
如果d<x.w,那么说明x及以后找不到比x.w小的更优解那么我们先记录这段的最大曼哈顿距离(\(ans=max(ans,d)\))然后往左找更优解。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, q, mi1[N], mx1[N], mi2[N], mx2[N], ans;
pair<int, pair<int, int>>p[N];

bool check(int id, int x, int y) {
    int d = max(abs(x + y - mi1[id]), abs(x + y - mx1[id]));
    d = max({ d, abs(x - y - mi2[id]), abs(x - y - mx2[id]) });
    if (d >= p[id].first) return true;
    ans = max(ans, d);
    return false;
}

void solve()
{
    cin >> n >> q;
    for (int i = 1, x, y, w; i <= n; i++) {
        cin >> x >> y >> w;
        p[i] = { w, {x, y} };
    }
    sort(p + 1, p + 1 + n);
    mi1[n] = mx1[n] = p[n].second.first + p[n].second.second;
    mi2[n] = mx2[n] = p[n].second.first - p[n].second.second;
    for (int i = n - 1; i >= 1; i--) {
        mi1[i] = min(mi1[i + 1], p[i].second.first + p[i].second.second);
        mx1[i] = max(mx1[i + 1], p[i].second.first + p[i].second.second);
        mi2[i] = min(mi2[i + 1], p[i].second.first - p[i].second.second);
        mx2[i] = max(mx2[i + 1], p[i].second.first - p[i].second.second);
    }
    
for (int i = 1, x, y; i <= q; i++) {
        cin >> x >> y;
        ans = min(p[1].first, abs(x - p[1].second.first) + abs(y - p[1].second.second));
        int l = 1, r = n;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (check(mid, x, y)) {
                ans = max(ans,  min(p[mid].first, abs(x - p[mid].second.first) + abs(y - p[mid].second.second)));
                l = mid + 1;
            }
            else r = mid - 1;
        }
        cout << ans << "\n";
    }
   
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int _t = 1;
    cin >> _t;
    while (_t--)
        solve();
    return 0;
}
posted @ 2022-09-29 00:43  Yaqu  阅读(42)  评论(0)    收藏  举报