4456: [Zjoi2016]旅行者

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 777  Solved: 439
[Submit][Status][Discuss]

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

HINT

Source

不想写题解了,发现BZOJ有题解,直接抄就完事了

  1. 实际上分块和分治的思想是差不多的,就直接讲分治吧。。
  2.  
  3. 首先转离线操作,然后对于某一个矩形区间x∈[lx,rx],y∈[ly,ry],然后要求出所有源点和汇点都在其中的询问,且路径不超出所在区间的答案。不妨设rx-lx>ly-ty,那么对x坐标进行分治,即将这个区间分成两块,那么对于某一个询问,有两种情况:
  4.  
  5. 1.如果询问的起点和终点在两个不同的块,那么一定会经过中轴线上的一点;
  6.  
  7. 2.如果在同一块,那么有可能经过中轴线;也有可能路径只在那一块中,就可以递归分治了;
  8.  
  9. 那么对于某一块,求出中轴线到所在块的所有点的距离,更新一下答案;然后递归分治。
  10.  
  11. 考虑用dijkstra+heap跑最短路,那么就大概是O(N^1.5logN)的(因为思想和kd-tree是差不多的吧所以时间也一样)。本地测试后两个点dijkstra+heap的时间接近spfa的一半
  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<cstdio>
  5. #include<queue>
  6. #include<cmath>
  7. #include<algorithm>
  8. #define maxn 20105
  9. using namespace std;
  10. inline int read() {
  11. int x=,f=;char ch=getchar();
  12. for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-;
  13. for(;isdigit(ch);ch=getchar()) x=x*+ch-'';
  14. return x*f;
  15. }
  16.  
  17. struct Node {
  18. int x,y,d;
  19. bool operator <(const Node &tmp) const {return d>tmp.d;}
  20. };
  21. struct query {int x1,y1,x2,y2,id;}a[],L[],R[];
  22. int ans[];
  23. int v[maxn][];
  24. int n,m,Q;
  25. int dis[maxn],vis[maxn];
  26. int tx[]={,-,,},ty[]={,,,-};
  27. priority_queue<Node> q;
  28. inline int get(int x,int y) {return (x-)*m+y;}
  29. inline void dij(int x,int y,int x1,int x2,int y1,int y2) {
  30. for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) dis[get(i,j)]=,vis[get(i,j)]=;
  31. q.push((Node){x,y,});
  32. dis[get(x,y)]=;
  33. while(!q.empty()) {
  34. Node now=q.top();q.pop();
  35. if(vis[get(now.x,now.y)]) continue;
  36. vis[get(now.x,now.y)]=;
  37. for(int i=;i<;i++) {
  38. int tox=now.x+tx[i],toy=now.y+ty[i];
  39. if(tox>x2||tox<x1||toy>y2||toy<y1) continue;
  40. if(dis[get(tox,toy)]>dis[get(now.x,now.y)]+v[get(now.x,now.y)][i]) {
  41. dis[get(tox,toy)]=dis[get(now.x,now.y)]+v[get(now.x,now.y)][i];
  42. q.push((Node){tox,toy,dis[get(tox,toy)]});
  43.  
  44. }
  45. }
  46. }
  47. }
  48. inline void solve(int x1,int x2,int y1,int y2,int ql,int qr) {
  49. if(qr<ql) return;
  50. if(x1==x2&&y1==y2) {
  51. for(int i=ql;i<=qr;i++) ans[a[i].id]=;
  52. return ;
  53. }
  54. if(x2-x1>y2-y1) {
  55. int mid=(x2+x1)>>;
  56. for(int i=y1;i<=y2;i++) {
  57. dij(mid,i,x1,x2,y1,y2);
  58. for(int j=ql;j<=qr;j++) ans[a[j].id]=min(ans[a[j].id],dis[get(a[j].x1,a[j].y1)]+dis[get(a[j].x2,a[j].y2)]);
  59. }
  60. int l=,r=;
  61. for(int i=ql;i<=qr;i++) {
  62. if(a[i].x1<=mid&&a[i].x2<=mid) L[++l]=a[i];
  63. if(a[i].x1>mid&&a[i].x2>mid) R[++r]=a[i];
  64. }
  65. for(int i=;i<=l;i++) a[ql+i-]=L[i];
  66. for(int i=;i<=r;i++) a[ql+l+i-]=R[i];
  67. solve(x1,mid,y1,y2,ql,ql+l-);solve(mid+,x2,y1,y2,ql+l,ql+l+r-);
  68. }
  69. else {
  70. int mid=(y2+y1)>>;
  71. for(int i=x1;i<=x2;i++) {
  72. dij(i,mid,x1,x2,y1,y2);
  73. for(int j=ql;j<=qr;j++) ans[a[j].id]=min(ans[a[j].id],dis[get(a[j].x1,a[j].y1)]+dis[get(a[j].x2,a[j].y2)]);
  74.  
  75. }
  76. int l=,r=;
  77. for(int i=ql;i<=qr;i++) {
  78. if(a[i].y1<=mid&&a[i].y2<=mid) L[++l]=a[i];
  79. if(a[i].y1>mid&&a[i].y2>mid) R[++r]=a[i];
  80. }
  81. for(int i=;i<=l;i++) a[ql+i-]=L[i];
  82. for(int i=;i<=r;i++) a[ql+l+i-]=R[i];
  83. solve(x1,x2,y1,mid,ql,ql+l-);solve(x1,x2,mid+,y2,ql+l,ql+l+r-);
  84. }
  85. }
  86. int main() {
  87. memset(v,,sizeof(v));
  88. n=read(),m=read();
  89. for(int i=;i<=n;i++) for(int j=;j<m;j++) v[get(i,j)][]=v[get(i,j+)][]=read();
  90. for(int i=;i<n;i++) for(int j=;j<=m;j++) v[get(i,j)][]=v[get(i+,j)][]=read();
  91. Q=read();
  92. for(int i=;i<=Q;i++) {
  93. a[i].x1=read(),a[i].y1=read(),a[i].x2=read(),a[i].y2=read();
  94. a[i].id=i;ans[i]=;
  95. }
  96. solve(,n,,m,,Q);
  97. for(int i=;i<=Q;i++) printf("%d\n",ans[i]);
  98. }

[BZOJ4456] [Zjoi2016]旅行者 分治+最短路的更多相关文章

  1. 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路

    [BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...

  2. 【BZOJ-4456】旅行者 分治 + 最短路

    4456: [Zjoi2016]旅行者 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 254  Solved: 162[Submit][Status] ...

  3. BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路

    原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html 题目传送门 - BZOJ4456 题目传送门 - UOJ#184 题意 $n\times ...

  4. 【BZOJ4456】旅行者(最短路,分治)

    [BZOJ4456]旅行者(最短路,分治) 题面 BZOJ Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些 ...

  5. bzoj4456: [Zjoi2016]旅行者

    题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...

  6. [BZOJ4456][ZJOI2016]旅行者:分治+最短路

    分析 类似于点分治的思想,只统计经过分割线的最短路,然后把地图一分为二. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(regist ...

  7. BZOJ4456 ZJOI2016旅行者(分治+最短路)

    感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...

  8. BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)

    题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...

  9. 4456: [Zjoi2016]旅行者

    4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...

随机推荐

  1. springboot的application.properties与.yml的区别

    现在我们的application.properties文件内容是: server.port=8090 server.session-timeout=30 server.context-path= se ...

  2. 深入探析 Rational AppScan Standard Edition 多步骤操作

    序言 IBM Rational AppScan Standard(下文简称 AppScan)作为面向 Web 应用安全黑盒检测的自动化工具,得到业界的广泛认可和应用.很多人使用 AppScan 时都采 ...

  3. Anaconda创建python(2.7/3.6)的虚拟环境后需要添加ipykernel

    今天在工作的过程中遇到这样一个问题:安装完Anaconda利用conda创建了虚拟环境,但是启动jupyter notebook之后却找不到虚拟环境中的python kernel.后来上网找到了解决办 ...

  4. HashMap详谈以及实现原理

    (一).HashMap 基于哈希表的 Map 接口的实现 允许使用 null 值和 null 键 HashMap不是线程安全,想要线程安全,Collections类的静态方法synchronizedM ...

  5. 【51NOD-0】1058 N的阶乘的长度

    [算法]数学 [题解]n!的位数相当于ans=log10(n!)上取整,然后就可以拆出来加了. 可以用log10(i)或log(i)/log(10) 阶乘好像有个斯特林公式…… #include< ...

  6. 如何设计一个优雅健壮的Android WebView?(下)

    转:如何设计一个优雅健壮的Android WebView?(下) 前言 在上文<如何设计一个优雅健壮的Android WebView?(上)>中,笔者分析了国内WebView的现状,以及在 ...

  7. css纯样式导航

    <style>.dropdown {    position: relative;    display: inline-block;} .dropdown-content {    di ...

  8. perl6 修改文件并覆盖

    use v6; my $filename = 'data.txt'; my $data = slurp $filename; say $data; $data ~~ s/'4'/'ABC'/; say ...

  9. Java21个基础知识点

    类装载器就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件.在Java中,类装载器把一个类装入JVM中,要经过以下步骤: (1) 装载:查找和导入Class文件: (2) 链接:把类的二进制 ...

  10. ThinkPHP5 正则验证中有“|”时提示“规则错误”的解决方案

    正则规则中有“|”时,会引起解析错误: 'regex:\d{3,4}[\s,-]?\d{7,8}|1[3,4,5,8]\d[\s,-]?\d{4}[\s,-]?\d{4}' 使用数组语法可以解决: [ ...