1 条题解
-
0
#include <bits/stdc++.h> using namespace std; // 原图 int F, M, N; int R; int dx[] = {0, 0, 0, 0, 1, -1}; int dy[] = {0, 0, 1, -1, 0, 0}; int dz[] = {1, -1, 0, 0, 0, 0}; // 获取第 p 层第 q 行第 r 列的编号 int getId(int p, int q, int r) { return (p - 1) * (M * N) + (q - 1) * M + r; } // 新图 const int MAXN = 200000 * 2; vector<int> e[MAXN + 5]; // 标黑色恐怖距离 queue<int> q; int w[MAXN + 5]; // 原图每个点的黑色恐怖距离 // 封装 LCA namespace LCA { int n, m, s; vector<int> e[MAXN + 5]; // f[i][j] 记录 i 的 2^j 级别祖先 int f[MAXN + 5][25]; // dep[i] 求节点 i 的深度 int dep[MAXN + 5]; // void clear(){} void addEdge(int u, int v) { e[u].push_back(v); e[v].push_back(u); } void dfs(int u, int fa) { f[u][0] = fa; for (int i = 0; i < e[u].size(); i++) { int v = e[u][i]; if (v == fa) continue; dep[v] = dep[u] + 1; dfs(v, u); } } void init() { dep[s] = 0; dfs(s, 0); // 预处理深度 dep[u],以及一级祖先 f[u][0] // i 的 2^j 级别祖先 = i 的 2^{j-1} 级别祖先的 2^{j-1} 级别祖先 for (int j = 1; (1LL << j) <= n; j++) for (int i = 1; i <= n; i++) f[i][j] = f[f[i][j - 1]][j - 1]; } int lca(int u, int v) { // 保证 u 在上面,v 在下面 if (dep[v] < dep[u]) swap(u, v); // 拉到同样的深度 for (int j = 20; j >= 0; j--) if (dep[v] - dep[u] >= (1 << j)) v = f[v][j]; // 初始两点之间是祖孙关系时,拉到同样深度就会变成同一个点 if (u == v) return u; // 同步往上走,跳到了 lca 下面一跳位 for (int j = 20; j >= 0; j--) if (f[u][j] != f[v][j]) u = f[u][j], v = f[v][j]; return f[u][0]; } } // Kruskal 重构树 // 存所有边 <-权值, <起点,终点>> vector<pair<int, pair<int, int>>> allEdge; int fa[MAXN + 5]; int findFa(int u) { if (fa[u] == u) return u; return fa[u] = findFa(fa[u]); } int ww[MAXN + 5]; // kruskal 重构树中每个点权值 int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> F >> N >> M; // 真的建出来图 for (int i = 1; i <= F; i++) for (int j = 1; j <= N; j++) for (int k = 1; k <= M; k++) { for (int fx = 0; fx < 6; fx++) { int ii = i + dx[fx]; int jj = j + dy[fx]; int kk = k + dz[fx]; if (ii < 1 || ii > F || jj < 1 || jj > N || kk < 1 || kk > M) continue; int u = getId(i, j, k); int v = getId(ii, jj, kk); e[u].push_back(v); e[v].push_back(u); } } // 标黑色恐怖距离 for (int i = 1; i <= F * M * N; i++) w[i] = -1; cin >> R; for (int i = 1; i <= R; i++) { int P, Q, R; cin >> P >> Q >> R; int u = getId(P, Q, R); q.push(u); w[u] = 0; } while (!q.empty()) { int u = q.front(); q.pop(); for (int v : e[u]) if (w[v] == -1) { w[v] = w[u] + 1; q.push(v); } } // Kruskal 重构树 // 遍历每条边 for (int u = 1; u <= F * M * N; u++) for (int v : e[u]) allEdge.push_back({-min(w[u], w[v]), {u, v}}); // 边从大到小排序(通过负边权实现) sort(allEdge.begin(), allEdge.end()); // 并查集初始化 for (int u = 1; u <= 2 * F * M * N; u++) fa[u] = u; // Kruskal,过程中把建立的新图放入 LCA LCA::n = F * N * M; // 初始的点数 for (int i = 0; i < allEdge.size(); i++) { int nowW = -allEdge[i].first; int u = allEdge[i].second.first; int v = allEdge[i].second.second; int faU = findFa(u); int faV = findFa(v); if (faU == faV) continue; LCA::n++; ww[LCA::n] = nowW; ww[u] = w[u]; ww[v] = w[v]; LCA::addEdge(LCA::n, faU); LCA::addEdge(LCA::n, faV); fa[faU] = fa[faV] = LCA::n; } LCA::s = LCA::n; LCA::init(); // 回答询问 int Q; cin >> Q; while (Q--) { int a, b, c, x, y, z; cin >> a >> b >> c >> x >> y >> z; int u = getId(a, b, c); int v = getId(x, y, z); cout << ww[LCA::lca(u, v)] << "\n"; } return 0; }
- 1
信息
- ID
- 13299
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 5
- 标签
- 递交数
- 51
- 已通过
- 4
- 上传者