題目大意 :
有一個 N * M 的矩陣, 每個值代表該點的山有多高, Q次詢問, 每次詢問兩點之間的路徑中, 經過的最大值的最小值是多少
(可以向上下左右四個方向走)
思路 :
首先1e5次詢問肯定不能直接暴力寫,不難想到建立MST, 那麼樹上的路徑即爲最短的路徑, 兩個點的路徑唯一, 在求LCA的過程中就可以求出路徑當中點權的最值問題了, 通過倍增可以讓最值維護優化, 但是要注意, LCA最後結束的時候還要對於x和y的點權取個最大值, 因爲LCA倍增算法是不斷逼近於最近共同祖先的, 無法直接到達, 所以纔會有 if (p[x][i] == p[y][i]) continue 這一步,這個BUG找了4個多小時, 最後如果兩個點相同, 輸出該點的高度就好
Accepted code
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 2e5 + 100;
const int MAXX = 2e6 + 100;
const int MAXM = 510;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
struct Edge
{
int v, w;
};
struct node
{
int x, y, w;
bool operator < (const node &oth) const
{
return w < oth.w;
}
}t[MAXX];
vector <Edge> e[MAXN << 1];
vector <int> s;
int dep[MAXN], p[MAXN][25], st[MAXN][25];
int n, m, q, tot;
int h[MAXM][MAXM], fa[MAXN];
int find_(int x) {
while (x != fa[x]) x = fa[x] = fa[fa[x]];
return x;
}
void unite(int x, int y) {
x = find_(x);
y = find_(y);
if (x != y) fa[x] = y;
}
void dfs(int x, int fa) {
dep[x] = dep[fa] + 1, p[x][0] = fa;
for (int i = 1; (1 << i) <= dep[x]; i++) {
p[x][i] = p[p[x][i - 1]][i - 1];
st[x][i] = max(st[x][i - 1], st[p[x][i - 1]][i - 1]);
}
for (int i = 0; i < SZ(e[x]); i++) {
int vi = e[x][i].v;
if (vi != fa) st[vi][0] = e[x][i].w, dfs(vi, x);
}
}
int LCA(int x, int y) {
int max_ = -INF;
if (dep[x] > dep[y]) swap(x, y);
for (int i = 20; i >= 0; i--) {
if (dep[y] - (1 << i) >= dep[x])
Max(max_, st[y][i]), y = p[y][i];
}
if (x == y) return max_;
for (int i = 20; i >= 0; i--) {
if (p[x][i] == p[y][i]) continue;
Max(max_, max(st[x][i], st[y][i]));
x = p[x][i], y = p[y][i];
}
return max(max_, max(st[x][0], st[y][0])); // 最後要取max
}
int main()
{
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
sc("%d", &h[i][j]);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
fa[(i - 1) * m + j] = (i - 1) * m + j;
int w1 = h[i][j], w2 = h[i][j + 1];
int w3 = h[i + 1][j];
int id1 = (i - 1) * m + j, id2 = (i - 1) * m + j + 1;
int id3 = i * m + j;
if (i < n) t[++tot] = { id1, id3, max(w1, w3) }; // 建圖
if (j < m) t[++tot] = { id1, id2, max(w1, w2) };
}
}
sort(t + 1, t + tot + 1);
int K = 0;
for (int i = 1; i <= tot; i++) {
if (K == n * m - 1) break;
int ui = t[i].x, vi = t[i].y, wi = t[i].w;
if (find_(ui) != find_(vi)) {
unite(ui, vi);
e[ui].push_back({ vi, wi });
e[vi].push_back({ ui, wi });
K++;
}
}
dfs(1, 0);
for (int i = 0; i < q; i++) {
int xi, yi, xx, yy;
sc("%d %d %d %d", &xi, &yi, &xx, &yy);
int ui = (xi - 1) * m + yi;
int vi = (xx - 1) * m + yy;
if (ui == vi) printf("%d\n", h[xi][yi]);
else printf("%d\n", LCA(ui, vi));
}
return 0; // 改數組大小!!!
}