#include #include "atcoder/dsu.hpp" #include "atcoder/segtree.hpp" using namespace std; const int INF = 1 << 30; const vector> dxy = {{0,1},{0,-1},{1,0},{-1,0}}; int op_min(int a, int b) { return min(a, b); } int e_min() { return INF; } int op_max(int a, int b) { return max(a, b); } int e_max() { return -INF; } vector order; vector depth; vector visited; void eulertour(const vector> &g) { int n = g.size(); visited = vector(n, 2*n); auto dfs = [&](auto self, int u, int d, int parent) -> void { if (visited[u] == 2*n) visited[u] = order.size(); order.push_back(u); depth.push_back(d); for (int v : g[u]) { if (v != parent) self(self, v, d+1, u); order.push_back(u); depth.push_back(d); } }; dfs(dfs, 0, 0, -1); return; } int main() { int h,w; cin >> h >> w; vector a(h, vector(w)); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { cin >> a[i][j]; } } vector> edges; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { for (auto [dx, dy] : dxy) { if (i+dx < 0 || i+dx >= h || j+dy < 0 || j+dy >= w) continue; edges.emplace_back(max(a[i][j], a[i+dx][j+dy]), i*w+j, (i+dx)*w+(j+dy)); } } } sort(edges.begin(), edges.end()); vector> g = [&]() { atcoder::dsu uf(h*w); vector> g(h*w); for (auto [cost, u, v] : edges) { if (!uf.same(u, v)) { uf.merge(u, v); g[u].push_back(v); g[v].push_back(u); } } return g; }(); eulertour(g); atcoder::segtree seg_depth(depth); auto lca = [&](int u, int v) -> int { if (visited[u] > visited[v]) swap(u, v); int min_depth = seg_depth.prod(visited[u], visited[v]+1); int lca_pos = seg_depth.max_right(visited[u], [&](int x) -> bool { return x > min_depth;}); return order[lca_pos]; }; int q; cin >> q; vector>> query(2*h*w); for (int i = 0; i < q; i++) { int rs, cs, rt, ct; cin >> rs >> cs >> rt >> ct; int u = (rs-1)*w+(cs-1); int v = (rt-1)*w+(ct-1); int l = lca(u, v); query[u].push_back({depth[visited[l]], i}); query[v].push_back({depth[visited[l]], i}); } atcoder::segtree seg_query(h*w); vector ans (q, -INF); auto dfs = [&] (auto self, int u, int parent) -> void { int val = a[u/w][u%w]; seg_query.set(depth[visited[u]], val); for (auto [d, id] : query[u]) { ans[id] = max(ans[id], seg_query.prod(d, h*w)); } for (auto v : g[u]) if (v != parent) self(self, v, u); seg_query.set(depth[visited[u]], -INF); }; dfs(dfs, 0, -1); for (auto x : ans) cout << x << '\n'; }