[国家集训队] 飞飞侠 题解

前言

题目链接:洛谷

题意分析

显然需要三次单源最短路,但不能朴素建图。曼哈顿转成切比雪夫,然后 KD-T 或二维线段树优化建图即可。

最多 \(\mathcal{O}(n^2\times n)\) 条边,时间复杂度 \(\mathcal{O}(n^3\log n)\)

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

using ll = long long;

template <typename T>
using minHeap = priority_queue<T, vector<T>, greater<T>>;

const int N = 150 + 10;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int n, m;
int b[N][N], a[N][N];

inline int id(int x, int y) {
    return (x - 1) * m + y;
}

struct P {
    int x, y;
    void R() {
        scanf("%d%d", &x, &y);
    }
    int operator()() const {
        return id(x, y);
    }
} X, Y, Z;

namespace sub1 {

bool check() {
    if (n > 100 || m > 100)
        return false;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            if (b[i][j] > 20)
                return false;
    return true;
}

const int N = 1e4 + 10;

vector<pair<int, int>> e[N];

ll dis[N];
ll solve(P x, P y1, P y2) {
    for (int i = 1; i <= n * m; ++i) {
        dis[i] = inf;
    }
    minHeap<pair<ll, int>> Q;
    Q.emplace(dis[x()] = 0, x());
    while (!Q.empty()) {
        ll ndis = Q.top().first;
        int u = Q.top().second;
        Q.pop();
        if (dis[u] < ndis) continue;
        for (auto E : e[u]) {
            int v = E.first;
            int w = E.second;
            if (dis[v] > dis[u] + w)
                Q.emplace(dis[v] = dis[u] + w, v);
        }
    }
    if (dis[y1()] == inf || dis[y2()] == inf)
        return inf;
    return dis[y1()] + dis[y2()];
}

void solve() {
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            for (int ti = max(1, i - b[i][j]); ti <= min(n, i + b[i][j]); ++ti)
                for (int tj = max(1, j - b[i][j]); tj <= min(m, j + b[i][j]); ++tj)
                    if (ti != i || tj != j) {
                        if (abs(i - ti) + abs(j - tj) > b[i][j])
                            continue;
                        // printf("(%d, %d) ---(%d)---> (%d, %d)\n", i, j, a[i][j], ti, tj);
                        e[id(ti, tj)].emplace_back(id(i, j), a[i][j]);
                    }
        }
    ll ans = inf, res;
    char chr = 0;
    if ((res = solve(X, Y, Z)) < ans) {
        ans = res;
        chr = 'X';
    }
    if ((res = solve(Y, X, Z)) < ans) {
        ans = res;
        chr = 'Y';
    }
    if ((res = solve(Z, X, Y)) < ans) {
        ans = res;
        chr = 'Z';
    }
    if (chr == 0) {
        puts("NO");
    } else {
        printf("%c\n%lld\n", chr, ans);
    }
}

}

namespace yzh {

// KD-T

const int M = 111900 * 3; // N * N * N * 4;
const int NM = M + N * N;

int rt, son[M][2], tot;

vector<pair<int, int>> e[NM];

void build(int &u, int xl, int xr, int yl, int yr) {
    if (xl == xr && yl == yr) {
        int x = xl, y = yl;
        if ((x + y) & 1) return;
        int a = (x + y) / 2;
        int b = (y - x) / 2;
        if (a < 1 || a > n || b < 1 || b > m) return;
        u = ++tot;
        e[id(a, b)].emplace_back(n * m + u, 0);
        return;
    }
    u = ++tot;
    if (xr - xl > yr - yl) {
        int mid = (xl + xr) >> 1;
        build(son[u][0], xl, mid, yl, yr);
        build(son[u][1], mid + 1, xr, yl, yr);
    } else {
        int mid = (yl + yr) >> 1;
        build(son[u][0], xl, xr, yl, mid);
        build(son[u][1], xl, xr, mid + 1, yr);
    }
    if (son[u][0])
        e[n * m + son[u][0]].emplace_back(n * m + u, 0);
    if (son[u][1])
        e[n * m + son[u][1]].emplace_back(n * m + u, 0);
}

void adde(int u, int txl, int txr, int tyl, int tyr, int xl, int xr, int yl, int yr, int x, int w) {
    if (!u) return;
    if (xl <= txl && txr <= xr && yl <= tyl && tyr <= yr) {
        e[n * m + u].emplace_back(x, w);
        return;
    }
    if (txr - txl > tyr - tyl) {
        int mid = (txl + txr) >> 1;
        if (xl <= mid) adde(son[u][0], txl, mid, tyl, tyr, xl, xr, yl, yr, x, w);
        if (xr > mid) adde(son[u][1], mid + 1, txr, tyl, tyr, xl, xr, yl, yr, x, w);
    } else {
        int mid = (tyl + tyr) >> 1;
        if (yl <= mid) adde(son[u][0], txl, txr, tyl, mid, xl, xr, yl, yr, x, w);
        if (yr > mid) adde(son[u][1], txl, txr, mid + 1, tyr, xl, xr, yl, yr, x, w);
    }
}

ll dis[NM];
ll solve(P x, P y1, P y2) {
    for (int i = 1; i <= n * m + tot; ++i) {
        dis[i] = inf;
    }
    minHeap<pair<ll, int>> Q;
    Q.emplace(dis[x()] = 0, x());
    while (!Q.empty()) {
        ll ndis = Q.top().first;
        int u = Q.top().second;
        Q.pop();
        if (dis[u] < ndis) continue;
        for (auto E : e[u]) {
            int v = E.first;
            int w = E.second;
            if (dis[v] > dis[u] + w)
                Q.emplace(dis[v] = dis[u] + w, v);
        }
    }
    if (dis[y1()] == inf || dis[y2()] == inf)
        return inf;
    return dis[y1()] + dis[y2()];
}

void adde(int xl, int xr, int yl, int yr, int x, int w) {
    xl = max(xl, 1 - m);
    xr = min(xr, n - 1);
    yl = max(yl, 2);
    yr = min(yr, n + m);
    if (xl > xr || yl > yr) return;
    adde(rt, 1 - m, n - 1, 1 + 1, n + m, xl, xr, yl, yr, x, w);
}

void solve() {
    build(rt, 1 - m, n - 1, 1 + 1, n + m);
    fprintf(stderr, "tot = %d\n", tot);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            if (b[i][j]) {
                adde(i - j - b[i][j], i - j + b[i][j], i + j - b[i][j], i + j + b[i][j], id(i, j), a[i][j]);
            }
        }
    ll ans = inf, res;
    char chr = 0;
    if ((res = solve(X, Y, Z)) < ans) {
        ans = res;
        chr = 'X';
    }
    fprintf(stderr, "res = %lld\n", res);
    if ((res = solve(Y, X, Z)) < ans) {
        ans = res;
        chr = 'Y';
    }
    fprintf(stderr, "res = %lld\n", res);
    if ((res = solve(Z, X, Y)) < ans) {
        ans = res;
        chr = 'Z';
    }
    fprintf(stderr, "res = %lld\n", res);
    if (chr == 0) {
        puts("NO");
    } else {
        printf("%c\n%lld\n", chr, ans);
    }
}

}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            scanf("%d", &b[i][j]);
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            scanf("%d", &a[i][j]);
        }
    }
    X.R(), Y.R(), Z.R();
#ifndef XuYueming
    if (sub1::check()) return sub1::solve(), 0;
#endif
    yzh::solve();
    return 0;
}

// g++ -O2 -Wall -Wextra -std=c++14 -DXuYueming 3.cpp -o 3
posted @ 2025-11-08 18:50  XuYueming  阅读(13)  评论(0)    收藏  举报