problem

luogu-P3350

solution

据说,网格图最短路用分治是一个人人皆知的套路。对不起我不是人

类比整体二分的算法流程。

考虑在一个 (xl,yl)−(yl,yr)(xl,yl)-(yl,yr)(xl,yl)−(yl,yr) 矩阵内处理 [ql,qr][ql,qr][ql,qr] 的询问。

以矩阵的中界线 mid\text{mid}mid 将矩阵划成两半,显然哪一维更长划哪一维。

以中界线上的每一个点为起点跑一遍最短路,然后更新所有需要跨过这条线的询问的答案,相当于是强制路线必须经过该点。

如果不需要跨过这条线,即询问的起终点均在线的某一侧,就分成 l,rl,rl,r 两个部分,继续分治下去。

时间复杂度好像都说是 O(NNlog⁡N)O(N\sqrt{N}\log N)O(NN​logN)。

具体见代码即可明白。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 20005
#define maxq 100005
#define Pair pair < int, int >
struct node { int u, v, id; }q[maxq], l[maxq], r[maxq];
vector < Pair > G[maxn];
priority_queue < Pair, vector < Pair >, greater < Pair > > que;
int x[maxn], y[maxn], dis[maxn], ans[maxq];
int n, m, Q;int id( int i, int j ) { return (i - 1) * m + j; }void dijkstra( int s, int xl, int xr, int yl, int yr ) {for( int i = xl;i <= xr;i ++ )for( int j = yl;j <= yr;j ++ )dis[id(i, j)] = 0x7f7f7f7f;que.push( make_pair( dis[s] = 0, s ) );while( ! que.empty() ) {int u = que.top().second, w = que.top().first;que.pop();if( dis[u] ^ w ) continue;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first; w = G[u][i].second;if( x[v] < xl or x[v] > xr or y[v] < yl or y[v] > yr ) continue;if( dis[v] > dis[u] + w )que.push( make_pair( dis[v] = dis[u] + w, v ) );}}
}void solve( int ql, int qr, int xl, int xr, int yl, int yr ) {if( ql > qr or xl > xr or yl > yr ) return;int cntl = 0, cntr = 0;if( xr - xl >= yr - yl ) {int mid = xr + xl >> 1;for( int i = yl;i <= yr;i ++ ) {dijkstra( id(mid, i), xl, xr, yl, yr );for( int j = ql;j <= qr;j ++ )ans[q[j].id] = min( ans[q[j].id], dis[q[j].u] + dis[q[j].v] );}for( int i = ql;i <= qr;i ++ ) {if( x[q[i].u] < mid and x[q[i].v] < mid ) l[++ cntl] = q[i];if( x[q[i].u] > mid and x[q[i].v] > mid ) r[++ cntr] = q[i];}for( int i = 1;i <= cntl;i ++ ) q[ql + i - 1] = l[i];for( int i = 1;i <= cntr;i ++ ) q[ql + cntl + i - 1] = r[i];solve( ql, ql + cntl - 1, xl, mid - 1, yl, yr );solve( ql + cntl, ql + cntl + cntr - 1, mid + 1, xr, yl, yr );}else {int mid = yr + yl >> 1;for( int i = xl;i <= xr;i ++ ) {dijkstra( id(i, mid), xl, xr, yl, yr );for( int j = ql;j <= qr;j ++ )ans[q[j].id] = min( ans[q[j].id], dis[q[j].u] + dis[q[j].v] );}for( int i = ql;i <= qr;i ++ ) {if( y[q[i].u] < mid and y[q[i].v] < mid ) l[++ cntl] = q[i];if( y[q[i].u] > mid and y[q[i].v] > mid ) r[++ cntr] = q[i];}for( int i = 1;i <= cntl;i ++ ) q[ql + i - 1] = l[i];for( int i = 1;i <= cntr;i ++ ) q[ql + cntl + i - 1] = r[i];solve( ql, ql + cntl - 1, xl, xr, yl, mid - 1 );solve( ql + cntl, ql + cntl + cntr - 1, xl, xr, mid + 1, yr );}
}int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ )for( int j = 1, x;j < m;j ++ ) {scanf( "%d", &x );G[id(i, j)].push_back( make_pair( id(i, j + 1), x ) );G[id(i, j + 1)].push_back( make_pair( id(i, j), x ) );}for( int i = 1;i < n;i ++ )for( int j = 1, x;j <= m;j ++ ) {scanf( "%d", &x );G[id(i, j)].push_back( make_pair( id(i + 1, j), x ) );G[id(i + 1, j)].push_back( make_pair( id(i, j), x ) );}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ )x[id(i, j)] = i, y[id(i, j)] = j;scanf( "%d", &Q );for( int i = 1, a1, b1, a2, b2;i <= Q;i ++ ) {scanf( "%d %d %d %d", &a1, &b1, &a2, &b2 );q[i] = (node){ id(a1, b1), id(a2, b2) }, q[i].id = i;}memset( ans, 0x7f, sizeof( ans ) );solve( 1, Q, 1, n, 1, m );for( int i = 1;i <= Q;i ++ ) printf( "%d\n", ans[i] );return 0;
}

[ZJOI2016]旅行者(网格图分治最短路)相关推荐

  1. [IOI2013]wombats(网格图分治+线段树+决策单调性)

    洛谷题目传送门 老话说的好,看见网格图,就想分治 我们对行进行分治 设当前分支节点是k,区间是 l [ k ] l[k] l[k]行到 r [ k ] r[k] r[k]行,他的分治子节点分别是 l ...

  2. Luogu3350 ZJOI2016 旅行者 最短路、分治

    传送门 题意:给出一个$N \times M$的网格图,边有边权,$Q$组询问,每组询问$(x_1,y_1)$到$(x_2,y_2)$的最短路.$N \times M \leq 2 \times 10 ...

  3. Leetcode69场双周赛-第四题5931. 用邮票贴满网格图

    5931. 用邮票贴满网格图 题目描述 解题思路 查找标志为0的点,尝试以该点为邮票的左上角,直到尝试为以该点为邮票的右下角.如果能放邮票,并覆盖该为0 的点,则把覆盖的点标志为2.如果不能,直接返回 ...

  4. 【数据结构与算法】之给Nx3网格图涂色的方案数的求解算法

    一.题目要求 你有一个 n x 3 的网格图 grid ,你需要用 红,黄,绿 三种颜色之一给每一个格子上色,且确保相邻格子颜色不同(也就是有相同水平边或者垂直边的格子颜色不同). 给你网格图的行数 ...

  5. MATLAB库函数polly2trellis(卷积码生成多项式转网格图描述)的实现过程详解

    关注公号[逆向通信猿]更精彩!!! 生成多项式转网格图 在MATLAB中,卷积码的维特比(Viterbi)译码实现通常需要先将生成多项式转换成网格图描述,然后才能利用网格图进行维特比译码 生成多项式转 ...

  6. Leetcode 1559二维网格图中探测环 技巧DFS|剪枝

    二维网格图中探测环 给你一个二维字符网格数组 grid ,大小为 m x n ,你需要检查 grid 中是否存在 相同值 形成的环. 一个环是一条开始和结束于同一个格子的长度 大于等于 4 的路径.对 ...

  7. LeetCode 2132. 用邮票贴满网格图(DP/二维差分)

    文章目录 1. 题目 2. 解题 1. 题目 给你一个 m x n 的二进制矩阵 grid ,每个格子要么为 0 (空)要么为 1 (被占据). 给你邮票的尺寸为 stampHeight x stam ...

  8. LeetCode 2087. 网格图中机器人回家的最小代价(脑筋急转弯)

    文章目录 1. 题目 2. 解题 1. 题目 给你一个 m x n 的网格图,其中 (0, 0) 是最左上角的格子,(m - 1, n - 1) 是最右下角的格子. 给你一个整数数组 startPos ...

  9. LeetCode 1411. 给 N x 3 网格图涂色的方案数(数学)

    1. 题目 你有一个 n x 3 的网格图 grid ,你需要用 红,黄,绿 三种颜色之一给每一个格子上色,且确保相邻格子颜色不同(也就是有相同水平边或者垂直边的格子颜色不同). 给你网格图的行数 n ...

最新文章

  1. 打造交叉复合型数据人才的高地:清华大学大数据能力提升项目宣讲会成功举行!...
  2. 运维经验分享:关于系统运维监控的几点建议
  3. oracle13c迁移,Oracle数据库迁移
  4. 【简便解法】1079 延迟的回文数 (20分)_31行代码AC
  5. c语言如何查找字符串指定字符
  6. npp夜光数据介绍 viirs_科研成果快报第177期:中国地区长时序AVHRR气溶胶数据的主要问题: 气溶胶反演频次与重污染天气...
  7. 今天听说了一个压缩解压整型的方式-group-varint
  8. 伪分布式Hadoop2.x集群的搭建1
  9. 用python进行数据分析--准备工作
  10. [转]Vue Cli3 + VS Code 愉快调试
  11. easyui 获取cloumns字段
  12. 华为将全面支持鸿蒙,华为鸿蒙 2.0正式发布!明年华为手机将全面支持
  13. 经典场景试题,测试用例编写
  14. 用计算机弹极乐净土谱,极乐净土计算器乐谱
  15. win10通过pe修复uefi引导后bootmanage出现两个引导项很烦人
  16. do sb suggest to_suggest_suggest to do 和 suggest doing 的区别
  17. 猫眼电影TOP100爬虫
  18. Ubuntu16.04运行LSD-SLAM
  19. 解析四种大数据文件格式
  20. QQ邮箱账号异常登录

热门文章

  1. 宝宝学数学的第一套书,秒杀题海战术!上小学前应该这样学数学!
  2. java继承接口和泛型,JavaSE习题 继承接口和泛型
  3. 流量节省模式 Android,这三种方法让你节省更多手机上网流量
  4. html怎么做交互留言,简单html与servlet交互
  5. phppage类封装分页功能_php显示页码分页类的封装
  6. mysql设计表月份_mysql,表设计
  7. mysql mysqladmin 介绍_Mysql—mysqladmin 命令详解
  8. [Swagger2]SpringBoot集成Swagger
  9. [MySQL基础]MySQL常见命令介绍
  10. 第七届蓝桥杯(国赛)——随意组合-dfs,next_permutation