Luogu3350 ZJOI2016 旅行者 最短路、分治
题意:给出一个$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 旅行者 最短路、分治的更多相关文章
- luogu3350 [ZJOI2016]旅行者
链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
- P3350 [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
- BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路
原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html 题目传送门 - BZOJ4456 题目传送门 - UOJ#184 题意 $n\times ...
- [BZOJ4456][ZJOI2016]旅行者:分治+最短路
分析 类似于点分治的思想,只统计经过分割线的最短路,然后把地图一分为二. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(regist ...
- BZOJ4456 ZJOI2016旅行者(分治+最短路)
感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...
随机推荐
- Android Java语法学习
Activity中有一个名称叫onCreate的方法.该方法是在Activity创建时被系统调用,是一个Activity生命周期的开始. onCreate方法的参数savedInstanceState ...
- mybatis学习系列四--mybatis generator逆向工程
采用命令行方式执行逆向工程 1.配置文件generatorConfig.xml 保存在目录:D:\E\workspace\eclipse\mybatis_generator <?xmlversi ...
- C#语言————两值交换
//两值交换 public static void Show(ref int num1,ref int num2) { int num=num1; num1=num2; num2=num; } sta ...
- Python实例---模拟微信网页登录(day5)
第六步: 实现发送/接受消息---day5代码 settings.py """ Django settings for weixin project. Generated ...
- java基础-温故而知新(02)
基本数据的自动拆装箱及享元设计模式 1.1 自动装箱 -128~127 之间的整数,装在一个内存区域. 超过这个范围的整数,装在不同的内存区域. 1.2 自动拆箱 ...
- 2.1Python数据处理篇之---内建有关数学的函数
目录 目录 前言 (一)数学相关得内建函数 (二)具体演示 1.求绝对值 2.创建一个复数 3.求商和余数 4.求x得y次幂 5.生成一个序列 6.四舍五入 7.对一个集合求和 8.求最大值 9.求最 ...
- Burp Suite 抓取http、https流量配置+CA证书安装
HTTPS协议是为了数据传输安全的需要,在HTTP原有的基础上,加入了安全套接字层SSL协议,通过CA证书来验证服务器的身份,并对通信消息进行加密.基于HTTPS协议这些特性,我们在使用Burp Pr ...
- 学生&部门智能匹配程序
Github链接 结对成员: 031502308 付逸豪 031502113 胡俊钦 数据生成 样例链接: 来点我啊 由于在生成数据的时候做了很多符合实际情况的限制,所以生成的数据都挺好的,就随便选了 ...
- Alpha冲刺! Day3 - 砍柴
Alpha冲刺! Day3 - 砍柴 今日已完成 晨瑶:补充安卓技能树: review接口文档:看了点七牛云安卓API. 昭锡:没有团队项目相关贡献. 永盛: API 文档基本完成:根据 API 文档 ...
- QT 11 鼠标键盘事件添加
鼠标事件 void mousePressEvent(QMouseEvent *event); //单击 void mouseReleaseEvent(QMouseEvent *event); //释放 ...