问题描述:
解题思路:
首先指出题目数据范围有问题,有n*m<=20000的数据范围没有指出。
令
S
=
n
∗
m
S=n*m
S=n∗m,考虑递归的处理。每次选择较长边进行切割,并枚举切割边上的点当作源点跑最短路,并解答询问。因为切割的是长边,源点不超过
S
\sqrt{S}
S。然后将询问递归到两个子矩形解决。
所以我们可以写出递归方程
T
(
S
)
=
2
T
(
S
/
2
)
+
S
S
log
2
S
T(S)=2T(S/2)+S\sqrt{S}\log_2S
T(S)=2T(S/2)+SSlog2S,根据主定理
T
(
S
)
=
O
(
S
S
log
2
S
)
T(S)=O(S\sqrt{S}\log_2S)
T(S)=O(SSlog2S)。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
void read(int &x) {
x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}
void write(ll x) {
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int N = 5e3 + 100;
const int M = 2e5 + 100;
struct node {
int x, y;
ll w;
node() {}
node(int x, int y, ll w) :x(x), y(y), w(w) {}
};
bool operator < (node a, node b) {
return a.w > b.w;
}
struct Qu {
int x1, y1, x2, y2, id;
};
int n, m, q;
vector<node> V[M];
ll dis[M], ans[M];
int get(int x, int y) {
return x * (m + 1) + y;
}
void clr(int xmi, int xma, int ymi, int yma) {
for (int i = xmi; i <= xma; i++)
for (int j = ymi; j <= yma; j++)
dis[get(i, j)] = 1e18;
}
void dijkstra(int xmi, int xma, int ymi, int yma, int sx, int sy) {
clr(xmi, xma, ymi, yma);
priority_queue<node> Q;
dis[get(sx, sy)] = 0;
Q.push(node(sx, sy, 0));
while (!Q.empty()) {
node r = Q.top(); Q.pop();
if (dis[get(r.x, r.y)] < r.w) continue;
ll id = get(r.x, r.y), v = r.w;
for (int i = 0; i < V[id].size(); i++) {
int x = V[id][i].x, y = V[id][i].y, c = V[id][i].w;
if (x < xmi || x > xma || y < ymi || y > yma) continue;
if (dis[get(x, y)] > v + c) {
dis[get(x, y)] = v + c;
Q.push(node(x, y, v + c));
}
}
}
}
void solve(int xmi, int xma, int ymi, int yma, vector<Qu> &V) {
if (xmi > xma || ymi > yma) return;
if (V.empty()) return;
if (xma - xmi > yma - ymi) {
int m = (xmi + xma) / 2;
for (int j = ymi; j <= yma; j++) {
dijkstra(xmi, xma, ymi, yma, m, j);
for (Qu q : V) {
ans[q.id] = min(ans[q.id], dis[get(q.x1, q.y1)] + dis[get(q.x2, q.y2)]);
}
}
vector<Qu> vl, vr, vv;
for (Qu q : V) {
if (q.x1 < m && q.x2 < m) vl.push_back(q);
if (q.x1 > m && q.x2 > m) vr.push_back(q);
}
V.clear();
swap(V, vv);
solve(xmi, m - 1, ymi, yma, vl);
solve(m + 1, xma, ymi, yma, vr);
}
else {
int m = (ymi + yma) / 2;
for (int i = xmi; i <= xma; i++) {
dijkstra(xmi, xma, ymi, yma, i, m);
for (Qu q : V) {
ans[q.id] = min(ans[q.id], dis[get(q.x1, q.y1)] + dis[get(q.x2, q.y2)]);
}
}
vector<Qu> vl, vr, vv;
for (Qu q : V) {
if (q.y1 < m && q.y2 < m) vl.push_back(q);
if (q.y1 > m && q.y2 > m) vr.push_back(q);
}
V.clear();
swap(V, vv);
solve(xmi, xma, ymi, m - 1, vl);
solve(xmi, xma, m + 1, yma, vr);
}
}
int main() {
//freopen("0.txt", "r", stdin);
int x; read(n); read(m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j < m; j++) {
read(x);
V[get(i, j)].push_back(node(i, j + 1, x));
V[get(i, j + 1)].push_back(node(i, j, x));
}
}
for (int i = 1; i < n; i++) {
for (int j = 1; j <= m; j++) {
read(x);
V[get(i, j)].push_back(node(i + 1, j, x));
V[get(i + 1, j)].push_back(node(i, j, x));
}
}
vector<Qu> V;
read(q);
for (int i = 1; i <= q; i++) {
Qu x;
read(x.x1); read(x.y1); read(x.x2); read(x.y2);
x.id = i;
V.push_back(x);
ans[i] = 1e18;
}
solve(1, n, 1, m, V);
for (int i = 1; i <= q; i++) write(ans[i]), puts("");
return 0;
}