●BOZJ 4456 [Zjoi2016]旅行者
题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=4456
题解:
分治好题。
大致做法如下:
对于一开始的矩形区域,过较长边的中点把矩形区域分为两个块。
然后依次以划分线上的点为起点跑最短路(Dijkstra),
尝试以该点为中转点去更新起点和终点都在这个矩形区域内的询问。
显然,如果某个询问的起点和终点在划分线的两侧,那么此时一定可以求出该询问的答案,
(因为其最短路一定会经过划分线上的点)。
那么至于起点和终点都在同侧的询问,那么就递归到更小的区域去求解是否有更优的答案,
(因为其最短路可能不经过当前划分线上的点)。
具体实现建议直接看代码。
(注意在每次Dijkstra前的操作,很巧妙,可以优化时间——我也是学习网上博主的。)
另外时间复杂度分析参见:http://blog.csdn.net/neither_nor/article/details/51733997
(但复杂度分析的最后一步化简我没看太懂,QAQ)
(不得不说,分治代码还真是考代码能力啊,调了老半天)
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 30000
#define MAXM 100050
#define INF 0x3f3f3f3f
#define idx(i,j) (i-1)*M+j
using namespace std;
typedef pair<int,int>pii;
struct Query{
int x1,y1,x2,y2,s,t,id;
}q[MAXM];
struct Edge{
int to[MAXM],val[MAXM],nxt[MAXM],head[MAXN],ent;
void Init(){ent=2;}
void Adde(int u,int v,int w){
to[ent]=v; val[ent]=w; nxt[ent]=head[u]; head[u]=ent++;
to[ent]=u; val[ent]=w; nxt[ent]=head[v]; head[v]=ent++;
}
int Next(int i,bool type){
return type?head[i]:nxt[i];
}
}E;
int N,M,Q;
int dis[MAXN],ans[MAXM],dx[MAXN],dy[MAXN];
void Dijkstra(int S,int X1,int Y1,int X2,int Y2,int w){
static bool vis[MAXN]; static int u,v;
static priority_queue<pii,vector<pii>,greater<pii> >H;
for(int i=X1;i<=X2;i++)
for(int j=Y1;j<=Y2;j++){
u=idx(i,j);
w==INF?dis[u]=INF:dis[u]+=w;
vis[u]=0;
}
dis[S]=0; H.push(make_pair(0,S));
while(!H.empty()){
u=H.top().second; H.pop();
if(vis[u]) continue; vis[u]=1;
for(int i=E.Next(u,1);i;i=E.Next(i,0)){
v=E.to[i];
if(dx[v]<X1||dx[v]>X2||dy[v]<Y1||dy[v]>Y2) continue;
if(dis[v]<=dis[u]+E.val[i]) continue;
dis[v]=dis[u]+E.val[i]; H.push(make_pair(dis[v],v));
}
}
}
void Partition(int X1,int Y1,int X2,int Y2,int ql,int qr){
static Query tmp[MAXM];
if(ql>qr||X1>X2||Y1>Y2) return;
if(X2-X1+1<=Y2-Y1+1){
int mid=(Y1+Y2)/2,L=ql,R=qr,S;
dis[idx(X1,mid)]=INF;
for(int i=X1;i<=X2;i++){
S=idx(i,mid);
Dijkstra(S,X1,Y1,X2,Y2,dis[S]);
for(int k=ql;k<=qr;k++)
ans[q[k].id]=min(ans[q[k].id],dis[q[k].s]+dis[q[k].t]);
}
for(int k=ql;k<=qr;k++){
if(q[k].y1<mid&&q[k].y2<mid) tmp[L++]=q[k];
if(q[k].y1>mid&&q[k].y2>mid) tmp[R--]=q[k];
}
for(int i=ql;i<L;i++) q[i]=tmp[i];
for(int i=qr;i>R;i--) q[i]=tmp[i];
Partition(X1,Y1,X2,mid-1,ql,L-1);
Partition(X1,mid+1,X2,Y2,R+1,qr);
}
else{
int mid=(X1+X2)/2,L=ql,R=qr,S;
dis[idx(mid,Y1)]=INF;
for(int j=Y1;j<=Y2;j++){
S=idx(mid,j);
Dijkstra(S,X1,Y1,X2,Y2,dis[S]);
for(int k=ql;k<=qr;k++)
ans[q[k].id]=min(ans[q[k].id],dis[q[k].s]+dis[q[k].t]);
}
for(int k=ql;k<=qr;k++){
if(q[k].x1<mid&&q[k].x2<mid) tmp[L++]=q[k];
if(q[k].x1>mid&&q[k].x2>mid) tmp[R--]=q[k];
}
for(int i=ql;i<L;i++) q[i]=tmp[i];
for(int i=qr;i>R;i--) q[i]=tmp[i];
Partition(X1,Y1,mid-1,Y2,ql,L-1);
Partition(mid+1,Y1,X2,Y2,R+1,qr);
}
}
int main()
{
freopen("tourist.in","r",stdin);
freopen("tourist.out","w",stdout);
E.Init();
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
dx[idx(i,j)]=i,dy[idx(i,j)]=j;
for(int i=1,w;i<=N;i++)
for(int j=1;j<M;j++)
scanf("%d",&w),E.Adde(idx(i,j),idx(i,j+1),w);
for(int i=1,w;i<N;i++)
for(int j=1;j<=M;j++)
scanf("%d",&w),E.Adde(idx(i,j),idx(i+1,j),w);
scanf("%d",&Q);
for(int i=1;i<=Q;i++){
scanf("%d%d%d%d",&q[i].x1,&q[i].y1,&q[i].x2,&q[i].y2);
q[i].s=idx(q[i].x1,q[i].y1);
q[i].t=idx(q[i].x2,q[i].y2);
q[i].id=i; ans[i]=INF;
}
Partition(1,1,N,M,1,Q);
for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
return 0;
}
●BOZJ 4456 [Zjoi2016]旅行者的更多相关文章
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
- bzoj 4456 [Zjoi2016]旅行者
题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解 分治 设当前work的区间为(x1,y1,x2,y2) 我们将长边分成两半 不妨 ...
- BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)
题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- P3350 [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- luogu3350 [ZJOI2016]旅行者
链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...
- Luogu 3350 [ZJOI2016]旅行者
BZOJ 4456 听若干个大佬讲过$n$遍终于写掉了. 我把时限基本上跑满了2333…… 分治 + 最短路. 首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然 ...
随机推荐
- socketpair创建双向通信的管道(全双工通信)
Linux下socketpair介绍: socketpair创建了一对无名的套接字描述符(只能在AF_UNIX域中使用),描述符存储于一个二元数组,例如sv[2] .这对套接字可以进行双工通信,每一个 ...
- mongodb 数据备份与恢复
备份 语法 mongodump -h dbhost -d dbname -o dbdirectory -h:服务器地址,也可以指定端口号 -d:需要备份的数据库名称 -o:备份的数据存放位置,此目录中 ...
- vivado License导入方法与资源获取
前言 以下安装说明基于已经正确安装vivado 笔者操作环境:linux vivado版本:2015.2 vivado License导入方法: 点击菜单栏[Help],选择[Manage Licen ...
- Echarts柱状图实现不同颜色渐变色
第一次写文,只是想记录一下自己平时发现的小功能,这篇主要是实现echarts柱状图,每个柱子实现不同颜色的渐变色,也是第一次接触echarts,后台使用ssm,前台是extjs,直接上效果图 直接上j ...
- css的内容
块级元素和行内元素的区别: 1. 行内元素部不能够设置宽度和高度.行内元素的宽度和高度是标签内容的宽度和高度.块级元素可以设置宽度和高度. 2. 块级元素会独占一行.而行内元素却部能够独占一行,只能和 ...
- 在bootstrap中让竖向排列的输入框水平排列
在bootstrap中可以使用自带的样式标记来控制样式,但是同时可以利用最原始的css样式来解决达到需求 如下所示可以看出来两个inline-block就可以使得两个水平排列 block和inline ...
- 剑指offer-二叉树中和为某一值的路径
题目描述 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径. 解题思路 利用前序遍历的思想,定义FindP ...
- 有货前端 Web-APM 实践
有货前端 Web-APM 实践 0 背景 有货电商技术架构上采用的是前后端分离,前端是主要以业务展示和接口聚合为主,拥有自己的 BFF (Backend For Frontend),以 nodejs ...
- 小tip: 使用CSS将图片转换成黑白(灰色、置灰)
可能早就知道,像汶川这种糟糕的日子网站全灰在IE下是可以轻松实现的(filter: gray;),不过,当时,其他浏览器是无解的.不过,时代发展,如今,CSS3的逐步推进,我们也开始看到“黑白效果”大 ...
- spring3——IOC之基于XML的依赖注入(DI )
我们知道spring容器的作用是负责对象的创建和对象间关系的维护,在上一篇博客中我们讲到spring容器会先调用对象的无参构造方法创建一个空值对象,那么接下来容器就会对对象的属性进行初始化,这个初始化 ...