[国家集训队] 飞飞侠 题解
前言
题目链接:洛谷。
题意分析
显然需要三次单源最短路,但不能朴素建图。曼哈顿转成切比雪夫,然后 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
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/19202882。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。

浙公网安备 33010602011771号