Description

小Y来到了一个新的城市旅行。她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北
的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m)。她发现不同的道路路况不同,所以通过不
同的路口需要不同的时间。通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1
,j)需要时间c(i,j)。注意这里的道路是双向的。小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要
花多少时间。

Input

第一行包含 2 个正整数n,m,表示城市的大小。
 
接下来n行,每行包含m?1个整数,第i行第j个正整数表示从一个路口到另一个路口的时间r(i,j)。
 
接下来n?1行,每行包含m个整数,第i行第j个正整数表示从一个路口到另一个路口的时间c(i,j)。
 
接下来一行,包含1个正整数q,表示小Y的询问个数。
 
接下来q行,每行包含4个正整数 x1,y1,x2,y2,表示两个路口的位置。

Output

输出共q行,每行包含一个整数表示从一个路口到另一个路口最少需要花的时间。

Sample Input

2 2
2
3
6 4
2
1 1 2 2
1 2 2 1

Sample Output

6
7

Solution

网格图求任意两点间的最短路。

可以用分治来解决。

之前校内训练的时候CJK学长出了一道IOI2013的题,就是用线段树来维护网格图的最短路。这题也很类似,离线询问以后,每次把长边拿出来分治,考虑经过中间这一排点的和没经过这一排点的。没经过的递归下去做,经过的就跑一遍堆优化dj或者spfa就好了。

Code

 #include <cstdio>
#include <cstring> #define R register
#define maxn 20010
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
#define id(_a, _b) (((_a) - 1) * m + (_b) - 1)
#define id1(_x) ((_x) / m + 1)
#define id2(_x) ((_x) % m + 1)
int n, m;
struct Edge {
Edge *next;
int to, w;
} *last[maxn], e[maxn << ], *ecnt = e;
inline void link(R int a, R int b, R int w)
{
*++ecnt = (Edge) {last[a], b, w}; last[a] = ecnt;
*++ecnt = (Edge) {last[b], a, w}; last[b] = ecnt;
}
struct Ques {
int x1, y1, x2, y2, id;
} qu[], tmp[];
int ans[], dis[maxn], q[maxn * ], r[maxn], c[maxn];
bool inq[maxn];
#define inf 0x7fffffff
struct Data {
int pos, dis;
inline bool operator < (const Data &that) const {return dis > that.dis;}
} ;
#include <queue>
std::priority_queue<Data> hp;
void spfa(R int s, R int nl, R int nr, R int ml, R int mr)
{
//for (R int i = nl; i <= nr; ++i) for (R int j = ml; j <= mr; ++j) dis[id(i, j)] = inf;
/*
R int head = maxn * 20, tail = maxn * 20 + 1;
q[maxn * 20 + 1] = s; dis[s] = 0;
*/
hp.push((Data) {s, dis[s] = });
while (/*head < tail*/!hp.empty())
{
// R int now = q[++head]; inq[now] = 0;
R Data tp = hp.top(); hp.pop();
R int now = tp.pos;
for (R Edge *iter = last[now]; iter; iter = iter -> next)
if (dis[iter -> to] > dis[now] + iter -> w && nl <= id1(iter -> to) && id1(iter -> to) <= nr && ml <= id2(iter -> to) && id2(iter -> to) <= mr)
{
dis[iter -> to] = dis[now] + iter -> w;
// !inq[iter -> to] ? inq[dis[iter -> to] < dis[q[head + 1]] ? q[head--] = iter -> to : q[++tail] = iter -> to] = 1 : 0;
hp.push((Data) {iter -> to, dis[iter -> to]});
}
}
}
void work(R int nl, R int nr, R int ml, R int mr, R int ql, R int qr)
{
if (nl > nr || ml > mr) return ;
if (ql > qr) return ;
if (nr - nl + <= mr - ml + )
{
R int mid = ml + mr >> ;
for (R int i = nl; i <= nr; ++i) for (R int j = ml; j <= mr; ++j) dis[id(i, j)] = inf;
for (R int i = nl; i <= nr; ++i)
{
if (i != nl)
{
for (R int ii = nl; ii <= nr; ++ii) for (R int jj = ml; jj <= mr; ++jj)
dis[id(ii, jj)] += c[id(i - , mid)];
}
spfa(id(i, mid), nl, nr, ml, mr);
for (R int j = ql; j <= qr; ++j)
cmin(ans[qu[j].id], dis[id(qu[j].x1, qu[j].y1)] + dis[id(qu[j].x2, qu[j].y2)]);
}
R int qql = ql - , qqr = qr + ;
for (R int i = ql; i <= qr; ++i)
if (qu[i].y1 < mid && qu[i].y2 < mid)
tmp[++qql] = qu[i];
else if (qu[i].y1 > mid && qu[i].y2 > mid)
tmp[--qqr] = qu[i]; for (R int i = ql; i <= qql; ++i) qu[i] = tmp[i];
for (R int i = qqr; i <= qr; ++i) qu[i] = tmp[i];
work(nl, nr, ml, mid - , ql, qql);
work(nl, nr, mid + , mr, qqr, qr);
}
else
{
R int mid = nl + nr >> ;
for (R int i = nl; i <= nr; ++i) for (R int j = ml; j <= mr; ++j) dis[id(i, j)] = inf;
for (R int i = ml; i <= mr; ++i)
{
if (i != ml)
{
for (R int ii = nl; ii <= nr; ++ii) for (R int jj = ml; jj <= mr; ++jj)
dis[id(ii, jj)] += r[id(mid, i - )];
}
spfa(id(mid, i), nl, nr, ml, mr);
for (R int j = ql; j <= qr; ++j)
cmin(ans[qu[j].id], dis[id(qu[j].x1, qu[j].y1)] + dis[id(qu[j].x2, qu[j].y2)]);
}
R int qql = ql - , qqr = qr + ;
for (R int i = ql; i <= qr; ++i)
if (qu[i].x1 < mid && qu[i].x2 < mid)
tmp[++qql] = qu[i];
else if (qu[i].x1 > mid && qu[i].x2 > mid)
tmp[--qqr] = qu[i]; for (R int i = ql; i <= qql; ++i) qu[i] = tmp[i];
for (R int i = qqr; i <= qr; ++i) qu[i] = tmp[i];
work(nl, mid - , ml, mr, ql, qql);
work(mid + , nr, ml, mr, qqr, qr);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (R int i = ; i <= n; ++i) for (R int j = ; j < m; ++j)
{R int w; scanf("%d", &w); link(id(i, j), id(i, j + ), w); r[id(i, j)] = w;}
for (R int i = ; i < n; ++i) for (R int j = ; j <= m; ++j)
{R int w; scanf("%d", &w); link(id(i, j), id(i + , j), w); c[id(i, j)] = w;}
R int Q; scanf("%d", &Q);
for (R int i = ; i <= Q; ++i) scanf("%d%d%d%d", &qu[i].x1, &qu[i].y1, &qu[i].x2, &qu[i].y2), qu[i].id = i;
memset(ans, , (Q + ) << );
work(, n, , m, , Q);
for (R int i = ; i <= Q; ++i) printf("%d\n", ans[i]);
return ;
}

最新文章

  1. Updatepanel 注册javascript 方法
  2. windows下pip升级到8.1.2
  3. LDAP过滤器使用说明(用户、组和容器的默认 LDAP 过滤器和属性)
  4. Linux文件权限学习总结
  5. web前端:html
  6. 如何使用 Android Studio 的 git hub 功能
  7. 在Windows下搭建React Native Android开发环境
  8. golang调试工具Delve
  9. zuul入门(1)zuul 的概念和原理
  10. BroadcastReceiver工作原理
  11. 如何相互转换逗号分隔的字符串和List【转】
  12. yolo3的改变
  13. 建议使用nginx配合uwsgi,
  14. 第六周 可执行代码 以及 PSP 燃尽图 等等
  15. c++ 类内部函数调用虚函数
  16. 拓扑排序获取所有可能序列JAVA实现
  17. SQL语句查询年龄分段分组查询
  18. Linux文件句柄数调整
  19. vue前端导出zip包
  20. logstash收集Nginx日志,转换为JSON格式

热门文章

  1. 小记---------spark架构原理&amp;主要组件和进程
  2. LOJ576 「LibreOJ NOI Round #2」签到游戏
  3. 从入门到自闭之Python列表,元祖及range
  4. spark教程(二)-shell操作
  5. WordPress网站搬家数据迁移完整教程
  6. solr学习笔记-增加mmesg4J中文分词
  7. Mysql主从分离介绍及实现
  8. 导出excel-文件流
  9. mysql的索引为什么要使用B+树而不是其他树?
  10. 帝国cms 通过文章的id获取信息