【BZOJ4456】旅行者(最短路,分治)
【BZOJ4456】旅行者(最短路,分治)
题面
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
题解
\(ZJOI\)上讲得题目
感觉很有意思
每次处理当前矩阵内的询问
将\(x,y\)两轴中较长的分成两半,使得矩阵尽可能“方”
如果一个询问的两个点跨越了这个中线,
则意味着答案一定经过了中线上的某个点
于是对中线上每个点跑一边对短路,
暴力更新答案
复杂度不会证明
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
const int inf=100000000;
int n,m,Q;
int dis[MAX];
int X[MAX],Y[MAX],ans[MAX];
bool vis[MAX];
int bh(int i,int j){return i*m+j-m;}
struct Line{int v,next,w;}e[200000];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w)
{
e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
e[cnt]=(Line){u,h[v],w};h[v]=cnt++;
}
struct Node{int i,dis;};
bool operator<(Node a,Node b){return a.dis>b.dis;}
void Dijkstra(int S,int lx,int ly,int rx,int ry)
{
priority_queue<Node> Q;
Q.push((Node){S,0});
for(int i=lx;i<=rx;++i)
for(int j=ly;j<=ry;++j)
dis[bh(i,j)]=inf,vis[bh(i,j)]=false;
while(!Q.empty())
{
int u=Q.top().i,D=Q.top().dis;Q.pop();
if(vis[u])continue;vis[u]=true;
dis[u]=D;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(!vis[v]&&lx<=X[v]&&X[v]<=rx&&ly<=Y[v]&&Y[v]<=ry)
Q.push((Node){v,dis[u]+e[i].w});
}
}
}
struct Query{int id,u,v;}q[MAX],tmp[MAX];
void Work(int lx,int rx,int ly,int ry,int L,int R)
{
if(L>R)return;
if(rx-lx>ry-ly)
{
int mid=(lx+rx)>>1;
for(int i=ly;i<=ry;++i)
{
Dijkstra(bh(mid,i),lx,ly,rx,ry);
for(int j=L;j<=R;++j)
ans[q[j].id]=min(ans[q[j].id],dis[q[j].u]+dis[q[j].v]);
}
int cntl=L-1,cntr=R+1;
for(int i=L;i<=R;++i)
{
int u=q[i].u,v=q[i].v;
if(X[u]<mid&&X[v]<mid)tmp[++cntl]=q[i];
if(X[u]>mid&&X[v]>mid)tmp[--cntr]=q[i];
}
for(int i=L;i<=R;++i)q[i]=tmp[i];
Work(lx,mid-1,ly,ry,L,cntl);
Work(mid+1,rx,ly,ry,cntr,R);
}
else
{
int mid=(ly+ry)>>1;
for(int i=lx;i<=rx;++i)
{
Dijkstra(bh(i,mid),lx,ly,rx,ry);
for(int j=L;j<=R;++j)
ans[q[j].id]=min(ans[q[j].id],dis[q[j].u]+dis[q[j].v]);
}
int cntl=L-1,cntr=R+1;
for(int i=L;i<=R;++i)
{
int u=q[i].u,v=q[i].v;
if(Y[u]<mid&&Y[v]<mid)tmp[++cntl]=q[i];
if(Y[u]>mid&&Y[v]>mid)tmp[--cntr]=q[i];
}
for(int i=L;i<=R;++i)q[i]=tmp[i];
Work(lx,rx,ly,mid-1,L,cntl);
Work(lx,rx,mid+1,ry,cntr,R);
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
X[bh(i,j)]=i,Y[bh(i,j)]=j;
for(int i=1;i<=n;++i)
for(int j=1;j<m;++j)
Add(bh(i,j),bh(i,j+1),read());
for(int i=1;i<n;++i)
for(int j=1;j<=m;++j)
Add(bh(i,j),bh(i+1,j),read());
Q=read();
for(int i=1;i<=Q;++i)
{
int xa=read(),ya=read(),xb=read(),yb=read();
q[i]=(Query){i,bh(xa,ya),bh(xb,yb)};
}
memset(ans,63,sizeof(ans));
Work(1,n,1,m,1,Q);
for(int i=1;i<=Q;++i)printf("%d\n",ans[i]);
return 0;
}
【BZOJ4456】旅行者(最短路,分治)的更多相关文章
- Luogu3350 ZJOI2016 旅行者 最短路、分治
传送门 题意:给出一个$N \times M$的网格图,边有边权,$Q$组询问,每组询问$(x_1,y_1)$到$(x_2,y_2)$的最短路.$N \times M \leq 2 \times 10 ...
- P5304 [GXOI/GZOI2019]旅行者(最短路/乱搞)
luogu bzoj Orz自己想出神仙正解的sxy 描述略 直接把所有起点推进去跑dijkstra... 并且染色,就是记录到这个点的最短路是由哪个起点引导出来的 然后再把所有边反指跑一次... 之 ...
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- 【BZOJ-4456】旅行者 分治 + 最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 254 Solved: 162[Submit][Status] ...
- BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路
原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html 题目传送门 - BZOJ4456 题目传送门 - UOJ#184 题意 $n\times ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- [BZOJ4456][ZJOI2016]旅行者:分治+最短路
分析 类似于点分治的思想,只统计经过分割线的最短路,然后把地图一分为二. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(regist ...
- BZOJ4456 ZJOI2016旅行者(分治+最短路)
感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...
- 2090. 「ZJOI2016」旅行者 分治,最短路
2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+dis(g ...
随机推荐
- arduino蜂鸣器的使用
一:蜂鸣器的使用 控制要求:模拟救护车响声 实物连接图: 电路原理图: 控制代码: //智慧自动化2018.6.11 ;//设置控制蜂鸣器的数字IO脚 void setup() { pinMode(b ...
- jenkens其实是代码上传工具
Jenkins 持续集成使用教程 用 jenkins 有什么好处 通过规范化来完成,简单,繁琐,浪费时间的重复工作 规范化工作,以免出现低级错误 实现随时随地任何人一键构建 ...... 安装 jen ...
- python-property、__get__、__set__
目录 property __set__ 和 __get__ property property装饰器的应用来自这样一个问题:如果对实例的属性值不加以限制,那么实例的属性值会出现明显不合理的情况,为了解 ...
- 搭建docker 私有镜像仓库
前期准备 服务器:centos 7.3 docker-ce: 18.06.1-ce docker-compose: 1.22.0 docker 安装 首先,更新系统 yum update yum up ...
- hdu - 6282,2018CCPC湖南全国邀请赛G题,字符串,规律
HDU – 6282 http://acm.hdu.edu.cn/showproblem.php?pid=6282 by Hzu_Tested 题意:给出两个字符串S和T,只由a,b,c三种字符组成( ...
- PytorchZerotoAll学习笔记(二)--梯度下降之手动求导
梯度下降算法: 待优化的损失值为 loss,那么我们希望预测的值能够很接近真实的值 y_pred ≍ y_label 我们的样本有n个,那么损失值可以由一下公式计算得出: 要使得los ...
- 数据挖掘学习笔记——kaggle 数据预处理
预处理 1. 删除缺失值 a. 删除行即样本(对于样本如果输出变量存在缺失的则直接删除该行,因为无法用该样本训练) b. 删除列,即特征(采用这种删除方式,应保证训练集和验证集都应当删除相同的特征) ...
- hashlib模块使用详情
python常用模块目录 一:hashlib简介 1.什么叫hash:hash是一种算法(不同的hash算法只是复杂度不一样)(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224 ...
- python format用法详解
#常用方法:print('{0},{1}'.format('zhangk', 32)) print('{},{},{}'.format('zhangk','boy',32)) print('{name ...
- Python中的构造函数
Python中的构造函数是__init__函数.在Python中,子类如果定义了构造函数,而没有调用父类的,那么Python不会自动调用,也就是说父类的构造函数不会执行. 比如有test.py的mod ...