Luogu3350 ZJOI2016 旅行者 最短路、分治

时间:2023-02-22 19:19:50

传送门

题意:给出一个$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 &lbrack;ZJOI2016&rsqb;旅行者

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

  2. &lbrack;BZOJ4456&rsqb; &lbrack;Zjoi2016&rsqb;旅行者 分治&plus;最短路

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

  3. 【BZOJ4456】&lbrack;Zjoi2016&rsqb;旅行者 分治&plus;最短路

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

  4. bzoj4456&colon; &lbrack;Zjoi2016&rsqb;旅行者

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

  5. 4456&colon; &lbrack;Zjoi2016&rsqb;旅行者

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

  6. P3350 &lbrack;ZJOI2016&rsqb;旅行者

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

  7. BZOJ4456&sol;UOJ&num;184&lbrack;Zjoi2016&rsqb;旅行者 分治 最短路

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

  8. &lbrack;BZOJ4456&rsqb;&lbrack;ZJOI2016&rsqb;旅行者:分治&plus;最短路

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

  9. BZOJ4456 ZJOI2016旅行者(分治&plus;最短路)

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

随机推荐

  1. GetReadyForWin10Develop

    GetReadyForWin10Develop 序言 今年4月29日晚的微软的Build大会上,微软在现场为我们演示了Android和IOS应用移植到windows平台,加上原本可以开发win8应用的 ...

  2. jQuery 判断所有图片加载完成

    对于图片的处理,例如幻灯片播放.缩放等,都是依赖于在所有图片完成之后再进行操作. 今天来看下如何判断所有的图片加载完成,而在加载完成之前可以使用 loading 的 gif 图表示正在加载中. 一.普 ...

  3. Xcode-程序开发设计-02九宫格

    行号是除 决定Y值 列号是余 决定X值 // // ViewController.m // 06-应用管理 // // Created by daier on 15/12/31. // Copyrig ...

  4. (转)SVN教程总结

    文章原地址:http://www.cnblogs.com/armyfai/p/3985660.html SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本, ...

  5. Codeforces 1091D New Year and the Permutation Concatenation 找规律&comma;数学 B

    Codeforces 1091D New Year and the Permutation Concatenation https://codeforces.com/contest/1091/prob ...

  6. Linux文件系统及文件类型

    Linux文件系统: 根文件系统(rootfs) root filesystem LSB, FHS: (FileSystem... /etc,  /usr,  /var,  /root.... /bo ...

  7. 探究Java中的锁

    一.锁的作用和比较 1.Lock接口及其类图 Lock接口:是Java提供的用来控制多个线程访问共享资源的方式. ReentrantLock:Lock的实现类,提供了可重入的加锁语义 ReadWrit ...

  8. topcoder srm 679 div1

    problem1 link $f[u][0],f[u][1]$表示$u$节点表示的子树去掉和不去掉节点$u$的最大权值. problem2 link 首先预处理计算任意三个蓝点组成的三角形中的蓝点个数 ...

  9. 移动web前端小结

    原文地址:http://blog.csdn.net/small_rice_/article/details/22690535 在智能手机横行的时代,作为一个web前端,不会编写移动web界面,的确是件 ...

  10. 【Loadrunner】Error -26601&colon; Decompression function 错误解决、27728报错解决方案

       一. Error -26601: Decompression function 错误解决 Action2.c(30): Error -26601: Decompression function ...