【BZOJ4456】 [Zjoi2016]旅行者 / 【UOJ #184】 【ZJOI2016】旅行者

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

  1 #include <cstdio>
  2 #include <cstring>
  3
  4 #define R register
  5 #define maxn 20010
  6 #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
  7 #define id(_a, _b) (((_a) - 1) * m + (_b) - 1)
  8 #define id1(_x) ((_x) / m + 1)
  9 #define id2(_x) ((_x) % m + 1)
 10 int n, m;
 11 struct Edge {
 12     Edge *next;
 13     int to, w;
 14 } *last[maxn], e[maxn << 4], *ecnt = e;
 15 inline void link(R int a, R int b, R int w)
 16 {
 17     *++ecnt = (Edge) {last[a], b, w}; last[a] = ecnt;
 18     *++ecnt = (Edge) {last[b], a, w}; last[b] = ecnt;
 19 }
 20 struct Ques {
 21     int x1, y1, x2, y2, id;
 22 } qu[100010], tmp[100010];
 23 int ans[100010], dis[maxn], q[maxn * 50], r[maxn], c[maxn];
 24 bool inq[maxn];
 25 #define inf 0x7fffffff
 26 struct Data {
 27     int pos, dis;
 28     inline bool operator < (const Data &that) const {return dis > that.dis;}
 29 } ;
 30 #include <queue>
 31 std::priority_queue<Data> hp;
 32 void spfa(R int s, R int nl, R int nr, R int ml, R int mr)
 33 {
 34 //for (R int i = nl; i <= nr; ++i) for (R int j = ml; j <= mr; ++j) dis[id(i, j)] = inf;
 35 /*
 36     R int head = maxn * 20, tail = maxn * 20 + 1;
 37     q[maxn * 20 + 1] = s; dis[s] = 0;
 38 */
 39     hp.push((Data) {s, dis[s] = 0});
 40     while (/*head < tail*/!hp.empty())
 41     {
 42 //        R int now = q[++head]; inq[now] = 0;
 43         R Data tp = hp.top(); hp.pop();
 44         R int now = tp.pos;
 45         for (R Edge *iter = last[now]; iter; iter = iter -> next)
 46             if (dis[iter -> to] > dis[now] + iter -> w && nl <= id1(iter -> to) && id1(iter -> to) <= nr && ml <= id2(iter -> to) && id2(iter -> to) <= mr)
 47             {
 48                 dis[iter -> to] = dis[now] + iter -> w;
 49 //                !inq[iter -> to] ? inq[dis[iter -> to] < dis[q[head + 1]] ? q[head--] = iter -> to : q[++tail] = iter -> to] = 1 : 0;
 50                 hp.push((Data) {iter -> to, dis[iter -> to]});
 51             }
 52     }
 53 }
 54 void work(R int nl, R int nr, R int ml, R int mr, R int ql, R int qr)
 55 {
 56     if (nl > nr || ml > mr) return ;
 57     if (ql > qr) return ;
 58     if (nr - nl + 1 <= mr - ml + 1)
 59     {
 60         R int mid = ml + mr >> 1;
 61         for (R int i = nl; i <= nr; ++i) for (R int j = ml; j <= mr; ++j) dis[id(i, j)] = inf;
 62         for (R int i = nl; i <= nr; ++i)
 63         {
 64             if (i != nl)
 65             {
 66                 for (R int ii = nl; ii <= nr; ++ii) for (R int jj = ml; jj <= mr; ++jj)
 67                     dis[id(ii, jj)] += c[id(i - 1, mid)];
 68             }
 69             spfa(id(i, mid), nl, nr, ml, mr);
 70             for (R int j = ql; j <= qr; ++j)
 71                 cmin(ans[qu[j].id], dis[id(qu[j].x1, qu[j].y1)] + dis[id(qu[j].x2, qu[j].y2)]);
 72         }
 73         R int qql = ql - 1, qqr = qr + 1;
 74         for (R int i = ql; i <= qr; ++i)
 75             if (qu[i].y1 < mid && qu[i].y2 < mid)
 76                 tmp[++qql] = qu[i];
 77             else if (qu[i].y1 > mid && qu[i].y2 > mid)
 78                 tmp[--qqr] = qu[i];
 79
 80         for (R int i = ql; i <= qql; ++i) qu[i] = tmp[i];
 81         for (R int i = qqr; i <= qr; ++i) qu[i] = tmp[i];
 82         work(nl, nr, ml, mid - 1, ql, qql);
 83         work(nl, nr, mid + 1, mr, qqr, qr);
 84     }
 85     else
 86     {
 87         R int mid = nl + nr >> 1;
 88         for (R int i = nl; i <= nr; ++i) for (R int j = ml; j <= mr; ++j) dis[id(i, j)] = inf;
 89         for (R int i = ml; i <= mr; ++i)
 90         {
 91             if (i != ml)
 92             {
 93                 for (R int ii = nl; ii <= nr; ++ii) for (R int jj = ml; jj <= mr; ++jj)
 94                     dis[id(ii, jj)] += r[id(mid, i - 1)];
 95             }
 96             spfa(id(mid, i), nl, nr, ml, mr);
 97             for (R int j = ql; j <= qr; ++j)
 98                 cmin(ans[qu[j].id], dis[id(qu[j].x1, qu[j].y1)] + dis[id(qu[j].x2, qu[j].y2)]);
 99         }
100         R int qql = ql - 1, qqr = qr + 1;
101         for (R int i = ql; i <= qr; ++i)
102             if (qu[i].x1 < mid && qu[i].x2 < mid)
103                 tmp[++qql] = qu[i];
104             else if (qu[i].x1 > mid && qu[i].x2 > mid)
105                 tmp[--qqr] = qu[i];
106
107         for (R int i = ql; i <= qql; ++i) qu[i] = tmp[i];
108         for (R int i = qqr; i <= qr; ++i) qu[i] = tmp[i];
109         work(nl, mid - 1, ml, mr, ql, qql);
110         work(mid + 1, nr, ml, mr, qqr, qr);
111     }
112 }
113 int main()
114 {
115     scanf("%d%d", &n, &m);
116     for (R int i = 1; i <= n; ++i) for (R int j = 1; j < m; ++j)
117         {R int w; scanf("%d", &w); link(id(i, j), id(i, j + 1), w); r[id(i, j)] = w;}
118     for (R int i = 1; i < n; ++i) for (R int j = 1; j <= m; ++j)
119         {R int w; scanf("%d", &w); link(id(i, j), id(i + 1, j), w); c[id(i, j)] = w;}
120     R int Q; scanf("%d", &Q);
121     for (R int i = 1; i <= Q; ++i) scanf("%d%d%d%d", &qu[i].x1, &qu[i].y1, &qu[i].x2, &qu[i].y2), qu[i].id = i;
122     memset(ans, 63, (Q + 1) << 2);
123     work(1, n, 1, m, 1, Q);
124     for (R int i = 1; i <= Q; ++i) printf("%d\n", ans[i]);
125     return 0;
126 }
时间: 2024-08-27 21:27:52

【BZOJ4456】 [Zjoi2016]旅行者 / 【UOJ #184】 【ZJOI2016】旅行者的相关文章

[CNBETA]动图告诉你 光速到底有多慢?

https://www.cnbeta.com/articles/tech/811381.htm 我们知道,30万公里每秒的光速是宇宙内目前已知的最高速度,至少现有人类理论体系下它是不可跨越的.30万公里每秒看起来快得不可思议,但宇宙实在是太大了,光速还是太慢太慢.为了让大家直观地理解光速到底有多慢,NASA科学家James O'donoghue特意制作了一组动图,说实话看完真有一种无力的绝望感. 地球赤道周长为39842公里,光每秒可以跑7.5圈. 地球和月球之间距离约为38.4万公里,光需要1

迪杰斯特拉的证明

[摘要]逆向思维是一种思考问题的方式,它有悖于通常人们的习惯,而正是这一特点,使得许多靠正常思维不能或是难于解决的问题迎刃而解.本文通过几个例子,总结了逆向思维在信息学解题中的应用. [关键字] 逆向思维容斥原理参数搜索 二分动态规划记忆化   [正文] 引言 我们先看一个简单的问题: 平面上有四个点,构成一个边长为1的正方形.现在进行一种操作,每次可以选择两个点A和B,把A关于B对称到C,然后把A去掉. 求证:不可能经过有限次操作得到一个边长大于1的正方形 操作后的结果是相当复杂的,如果我们从

bzoj4456 [Zjoi2016]旅行者

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)最少需要花多少

【ZJOI2016】旅行者

题面 https://www.luogu.org/problem/P3350 网格图上最短路 题解 离线+分治. 最短路两种情况,穿过中间边和没穿过中间边. 对于当前区域包含的询问: 先找当前区域中间边(尽可能切成正方形) 对中间边上的点,求当前区域内所有的点对其的最短路. 如果两点被中间边切断,那这次一定能得到最优解,可以去掉. 如果两点没被中间边切断,递归下去. // luogu-judger-enable-o2 #include<cstdio> #include<cstring&g

uoj #185. 【ZJOI2016】小星星

#185. [ZJOI2016]小星星 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有 nn 颗小星星,用 mm 条彩色的细线串了起来,每条细线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了 n−1n−1 条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树. 小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星.如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上

黯淡蓝点:旅行者号64亿公里外回望地球...

1990年“旅行者”号探测器在即将飞出太阳系的时候,最后一次回眸我们的家园--地球! “旅行者”号探测器从40亿英里(约64亿公里)之外拍摄了上面两张地球照片.第一张照片中,地球仅是一个0.12个像素大小的圆点.著名天文学家卡尔·萨根将其描绘成“硕大的宇宙夜幕中一个孤独的圆点,对我来说,它强调了我们在更友善.更积极地处理相互之间的关系上的责任,以及保护和爱惜这个黯淡蓝点的责任,这是人类已知的唯一家园.” 地球是在这个浩翰宇宙剧院里的一个细小舞台. 想想从那些将令们和皇帝们溢出的血河,他们的光荣与

【NOIP考前模拟赛】纯数学方法推导——旅行者问题

一.写在前面 这题似乎是一道原创题目(不是博主原创),所以并不能在任何OJ上评测,博主在网盘上上传了数据(网盘地址:http://pan.baidu.com/s/1mibdMXi),诸位看官需者自取.另外博主使用此题并没有获得出题人授权,如果出题人看到这篇blog并认为在下侵犯了您的权利,请用站内消息与在下联系,在下会立即删除这篇blog,给您带来的困扰之处敬请谅解. 博主上传这道题主要是因为这题牵扯许多数学运算,推导过程比较复杂,但是却没有用到任何算法或者数学定理,可以说这是一道想法题的典范.

NOIP模拟赛-旅行者问题 解题报告

题目 :http://www.tsinsen.com/P9143 题是我发现.想测可以测.已经分享出去了. 旅行者问题 [问题描述] lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行.lahub想去参观n个目的地(都在一条直道上).lahub在起点开始他的旅行.第i个目的地和起点的距离为ai千米(ai为非负整数).不存在两个目的地和起点的距离相同. 从第i个目的地走到第j个目的地所走的路程为 |ai-aj|千米.我们把参观n个目的地的顺序称作一次“旅行”.lahub

ZJOI2016

首先做了T2的旅行者,看到bz上面过的人数比较多.. 考试的时候完全没有想太多.一闪而过了分块思想,然后就没有然后了.. 大视野上面有题解,竟然是一个初中生写的..? 正解其实是“分治”,每次选择中轴线,不会势能分析,感觉考场上想出来也肯定不敢打.. #include<cstdio> #include<algorithm> #define inf 1000000000 #define N 100010 using namespace std; int dis[N],ans[N],q