传送门

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


BZOJ原题竟然没有数据范围

矩形的多组询问问题考虑分治。考虑计算矩形$(x_1,y_1,x_2,y_2)$的询问,我们将较长边沿着中线劈成两半,在这些询问里面就只可能存在两种情况:①询问的两个端点在中线两边,那么路径就一定会经过中线上一点;②询问的两个端点在中线的同一边,那么有可能不会经过中线,也有可能经过中线。所以我们对中线上所有的点跑一边整个矩形的最短路,每一次跑完最短路就更新所有的询问,然后再递归进入两侧矩形回答②类型的询问。时间复杂度似乎是$O(NM \times \sqrt{NM} \times log(NM))$

在$Luogu$题解上学到的一个加速方法:从一个点的最短路转移到新的点跑最短路的时候,可以不将最短路数组赋值为极大值,而是赋值为这一个点经过上一个计算的点到达所有目标点的答案。

(然而还是在Luogu不开O2的情况下TLE)

 // luogu-judger-enable-o2
//This code is written by Itst
#include<bits/stdc++.h>
#define pos(i,j) ((i-1)*M+j)
using namespace std; inline int read(){
int a = ;
bool f = ;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = ;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << ) + (a << ) + (c ^ '');
c = getchar();
}
return f ? -a : a;
} const int MAXN = ;
int cntEd , N , M , Q , minDis[MAXN] , ans[MAXN] , head[MAXN];
struct Edge{
int end , upEd , w;
}Ed[MAXN << ];
struct query{
int sx , sy , ex , ey , ind;
}now[MAXN] , pot[MAXN];
priority_queue < pair < int , int > > q; inline void addEd(int a , int b , int c){
Ed[++cntEd].end = b;
Ed[cntEd].w = c;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
} void Dijk(int bx , int by , int lx , int ly , int rx , int ry , int l){
int temp = minDis[pos(bx , by)];
for(int i = lx ; i <= rx ; i++)
for(int j = ly ; j <= ry ; j++)
minDis[pos(i , j)] = l == ? 0x3f3f3f3f : minDis[pos(i , j)] + temp;
minDis[pos(bx , by)] = ;
q.push(make_pair( , pos(bx , by)));
while(!q.empty()){
pair < int , int > t = q.top();
q.pop();
if(minDis[t.second] != -t.first)
continue;
for(int i = head[t.second] ; i ; i = Ed[i].upEd)
if(minDis[Ed[i].end] > minDis[t.second] + Ed[i].w){
minDis[Ed[i].end] = minDis[t.second] + Ed[i].w;
q.push(make_pair(-minDis[Ed[i].end] , Ed[i].end));
}
}
} void solve(int lx , int ly , int rx , int ry , int ql , int qr){
if(ql > qr)
return;
if(rx - lx > ry - ly){
int mid = lx + rx >> ;
for(int i = ly ; i <= ry ; i++){
Dijk(mid , i , lx , ly , rx , ry , i - ly);
for(int j = ql ; j <= qr ; j++)
ans[now[j].ind] = min(ans[now[j].ind] , minDis[pos(now[j].sx , now[j].sy)] + minDis[pos(now[j].ex , now[j].ey)]);
}
int p1 = ql , p2 = qr;
for(int i = ql ; i <= qr ; i++)
if(now[i].sx < mid && now[i].ex < mid)
pot[p1++] = now[i];
else
if(now[i].sx > mid && now[i].ex > mid)
pot[p2--] = now[i];
memcpy(now + ql , pot + ql , sizeof(query) * (qr - ql + ));
solve(lx , ly , mid , ry , ql , p1 - );
solve(mid + , ly , rx , ry , p2 + , qr);
}
else{
int mid = ly + ry >> ;
for(int i = lx ; i <= rx ; i++){
Dijk(i , mid , lx , ly , rx , ry , i - lx);
for(int j = ql ; j <= qr ; j++)
ans[now[j].ind] = min(ans[now[j].ind] , minDis[pos(now[j].sx , now[j].sy)] + minDis[pos(now[j].ex , now[j].ey)]);
}
int p1 = ql , p2 = qr;
for(int i = ql ; i <= qr ; i++)
if(now[i].sy < mid && now[i].ey < mid)
pot[p1++] = now[i];
else
if(now[i].sy > mid && now[i].ey > mid)
pot[p2--] = now[i];
memcpy(now + ql , pot + ql , sizeof(query) * (qr - ql + ));
solve(lx , ly , rx , mid , ql , p1 - );
solve(lx , mid + , rx , ry , p2 + , qr);
}
} int main(){
#ifdef LG
freopen("3350.in" , "r" , stdin);
freopen("3350.out" , "w" , stdout);
#endif
memset(ans , 0x3f , sizeof(ans));
N = read();
M = read();
for(int i = ; i <= N ; i++)
for(int j = ; j < M ; j++){
int t = read();
addEd(pos(i , j) , pos(i , j + ) , t);
addEd(pos(i , j + ) , pos(i , j) , t);
}
for(int i = ; i < N ; i++)
for(int j = ; j <= M ; j++){
int t = read();
addEd(pos(i , j) , pos(i + , j) , t);
addEd(pos(i + , j) , pos(i , j) , t);
}
Q = read();
for(int i = ; i <= Q ; i++){
now[i].sx = read();
now[i].sy = read();
now[i].ex = read();
now[i].ey = read();
now[i].ind = i;
}
solve( , , N , M , , Q);
for(int i = ; i <= Q ; i++)
printf("%d\n" , ans[i]);
return ;
}

Luogu3350 ZJOI2016 旅行者 最短路、分治的更多相关文章

  1. luogu3350 [ZJOI2016]旅行者

    链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...

  2. [BZOJ4456] [Zjoi2016]旅行者 分治+最短路

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

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

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

  4. bzoj4456: [Zjoi2016]旅行者

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

  5. 4456: [Zjoi2016]旅行者

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

  6. P3350 [ZJOI2016]旅行者

    题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...

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

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

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

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

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

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

随机推荐

  1. Android 裁剪人脸

    人脸裁剪类 public final class FaceCj { private static BitmapFactory.Options BitmapFactoryOptionsbfo; priv ...

  2. Session Cookies随笔

    1.对于Session而言 它是用来保存在服务端的信息,可以用来做登录验证,在后台保存有用信息. 一个浏览器访问一个网站,就是建立一个连接,连接信息是独立的,就是在该建立的连接内,保存到Session ...

  3. Oracle EBS FA 资产取值

    SELECT fb.book_type_code, fth.ASSET_NUMBER, fdh.units_assigned, fdh.assigned_to, pf.FULL_NAME, fl.se ...

  4. 始终使用属性(Property),而不是字段(Data Member)

    1.始终使用属性(Property),而不是字段(Data Member) C# 属性已经晋升为一等公民,如果你的类中还有public的字段,Stop.访问属性和字段的方式是一样的,但是属性是用方法( ...

  5. windows防火墙安全设置指定ip访问指定端口

    场景摘要: 1.我有三台腾讯云服务器 2.我日常办公网络的ip换了 3.我在腾讯云上面改了安全规则,也不能访问我A服务器的21,1433等端口 4.开始我以为是办公网络的安全设置问题 5.我进B服务器 ...

  6. emacs org-mode文件转html文件

    Table of Contents 1. 发布站点 by emacs org-mode 1.1 org-mode 自带的导出方法 1.2 批量导出 1.3 css 美化 1.4 导出html 1. 发 ...

  7. PJ可能会用到的动态规划选讲-学习笔记

    PJ可能会用到的动态规划选讲-学习笔记 by Pleiades_Antares 难度和速度全部都是按照普及组来定的咯 数位状压啥就先不讲了 这里主要提到的都是比较简单的DP 一道思维数学巧题(补昨天) ...

  8. if语句(初学者)

    用if语句可以构成分支结构.它根据给定的条件进行判断,以决定执行某个分支程序段.C语言的if语句有三种基本形式. 1.基本形式:if(表达式)语句 其语义是:如果表达式的值为真,则执行其后的语句,否则 ...

  9. MarkDown 排版测试

    大标题 小标题(正常) 小标题(多一杠) 一级标题 二级标题 三级标题 四级标题(未空格) 四级标题(正常) 个人编程,写一个命令行程序 注册Github账号,建立项目仓库 添加ReadMe.md并编 ...

  10. CyclicBarrier源码解读

    1. 简介 JUC中的CyclicBarrier提供了一种多线程间的同步机制,可以让多个线程在barrier等待其它线程到达barrier.正如其名CyclicBarrier含义就是可以循环使用的屏障 ...