1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
struct DSU {
vector<int> parent, compSize;
DSU(int n) : parent(n), compSize(n, 1) {
iota(parent.begin(), parent.end(), 0);
}
int find(int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
bool unite(int a, int b) {
a = find(a); b = find(b);
if (a == b) return false;
if (compSize[a] < compSize[b]) swap(a, b);
parent[b] = a;
compSize[a] += compSize[b];
return true;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m, n, q;
if (!(cin >> m >> n >> q)) return 0;
const int N = m * n;
vector<int> height(N);
vector<pair<int,int>> cells; cells.reserve(N);
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int h; cin >> h;
int id = i * n + j;
height[id] = h;
cells.emplace_back(h, id);
}
}
vector<pair<int,int>> query_pairs(q);
for (int i = 0; i < q; ++i) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
--x1; --y1; --x2; --y2;
query_pairs[i] = {x1 * n + y1, x2 * n + y2};
}
sort(cells.begin(), cells.end()); // by height asc
DSU dsu(N);
vector<char> active(N, 0);
vector<vector<pair<int,int>>> adj(N);
const int dr[4] = {-1, 1, 0, 0};
const int dc[4] = {0, 0, -1, 1};
for (auto &p : cells) {
int id = p.second;
int r = id / n, c = id % n;
active[id] = 1;
for (int k = 0; k < 4; ++k) {
int nr = r + dr[k], nc = c + dc[k];
if (nr < 0 || nr >= m || nc < 0 || nc >= n) continue;
int nid = nr * n + nc;
if (!active[nid]) continue;
int w = max(height[id], height[nid]);
if (dsu.unite(id, nid)) {
adj[id].push_back({nid, w});
adj[nid].push_back({id, w});
}
}
}
const int LOG = 20;
vector<int> depth(N, -1);
vector<array<int,LOG>> up(N);
vector<array<int,LOG>> mx(N);
for (int i = 0; i < N; ++i) {
for (int k = 0; k < LOG; ++k) {
up[i][k] = -1;
mx[i][k] = 0;
}
}
// BFS to set depth and 1st ancestors
queue<int> qu;
int root = 0;
depth[root] = 0;
qu.push(root);
while (!qu.empty()) {
int u = qu.front(); qu.pop();
for (auto &e : adj[u]) {
int v = e.first, w = e.second;
if (depth[v] != -1) continue;
depth[v] = depth[u] + 1;
up[v][0] = u;
mx[v][0] = w;
qu.push(v);
}
}
// Binary lifting tables
for (int k = 1; k < LOG; ++k) {
for (int v = 0; v < N; ++v) {
if (up[v][0] == -1) continue;
int mid = up[v][k - 1];
if (mid == -1) continue;
up[v][k] = up[mid][k - 1];
mx[v][k] = max(mx[v][k - 1], mx[mid][k - 1]);
}
}
auto maxOnPath = [&](int u, int v) {
if (u == v) return 0;
int ans = 0;
if (depth[u] < depth[v]) swap(u, v);
int diff = depth[u] - depth[v];
for (int k = 0; k < LOG; ++k) {
if (diff & (1 << k)) {
ans = max(ans, mx[u][k]);
u = up[u][k];
}
}
if (u == v) return ans;
for (int k = LOG - 1; k >= 0; --k) {
if (up[u][k] != -1 && up[u][k] != up[v][k]) {
ans = max(ans, mx[u][k]);
ans = max(ans, mx[v][k]);
u = up[u][k];
v = up[v][k];
}
}
ans = max(ans, mx[u][0]);
ans = max(ans, mx[v][0]);
return ans;
};
ostringstream out;
for (int i = 0; i < q; ++i) {
int s = query_pairs[i].first, t = query_pairs[i].second;
int bottleneck = maxOnPath(s, t);
int ans = max(bottleneck, max(height[s], height[t]));
out << ans << '\n';
}
cout << out.str();
return 0;
}
|