【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
【BZOJ4456】[Zjoi2016]旅行者
Description
Input
Output
Sample Input
2
3
6 4
2
1 1 2 2
1 2 2 1
Sample Output
7
题解:能把各种各样奇怪的做法和最短路结合起来我也是服了~
思考怎么分治,如果矩形的x2-x1>y2-y1,那么我们就按x分治,因为此时一列的点数是小于sqrt(n)的,所以我们可以枚举分割线上的所有点,以这些点为源点都跑一次最短路,然后考虑每个询问:
如果询问的两个点在分治的不同侧,则最短路可能经过分割线上的每个点,用分割线上每个点到这两个点的距离和更新答案,然后这个询问我们就不用管了。
如果询问的两个点在分治的同侧,则最短路也可能经过分割线上的点,依旧要更新答案,然后将这个询问放到对应的分治结构去。
所以最终的复杂度是$O(n \sqrt{n} log(n))$的。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define P(A,B) ((A-1)*m+B)
using namespace std;
const int maxn=20010;
int n,m,Q;
int dis[maxn],v[maxn][4],vis[maxn],ans[100010];
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
struct query
{
int x1,y1,x2,y2,org;
}q[100010],q1[100010],q2[100010];
struct node
{
int val,x,y;
node() {}
node(int a,int b,int c) {val=a,x=b,y=c;}
bool operator < (const node &a) const
{
return val>a.val;
}
};
priority_queue<node> pq;
void dijkstra(int sx,int sy,int lx,int rx,int ly,int ry)
{
int i,j,x,y,tx,ty;
for(i=lx;i<=rx;i++) for(j=ly;j<=ry;j++) dis[P(i,j)]=1<<30,vis[P(i,j)]=0;
dis[P(sx,sy)]=0,pq.push(node(0,sx,sy));
while(!pq.empty())
{
x=pq.top().x,y=pq.top().y,pq.pop();
if(vis[P(x,y)]) continue;
vis[P(x,y)]=1;
for(i=0;i<4;i++)
{
tx=x+dx[i],ty=y+dy[i];
if(tx>=lx&&tx<=rx&&ty>=ly&&ty<=ry&&dis[P(tx,ty)]>dis[P(x,y)]+v[P(x,y)][i])
{
dis[P(tx,ty)]=dis[P(x,y)]+v[P(x,y)][i];
pq.push(node(dis[P(tx,ty)],tx,ty));
}
}
}
}
void solve(int lx,int rx,int ly,int ry,int lq,int rq)
{
if(lq>rq) return ;
if(lx==rx&&ly==ry)
{
for(int i=lq;i<=rq;i++) ans[q[i].org]=0;
return ;
}
if(rx-lx>ry-ly)
{
int i,j,mid=(lx+rx)>>1,h1=0,h2=0;
for(i=ly;i<=ry;i++)
{
dijkstra(mid,i,lx,rx,ly,ry);
for(j=lq;j<=rq;j++) ans[q[j].org]=min(ans[q[j].org],dis[P(q[j].x1,q[j].y1)]+dis[P(q[j].x2,q[j].y2)]);
}
for(i=lq;i<=rq;i++)
{
if(q[i].x1<=mid&&q[i].x2<=mid) q1[++h1]=q[i];
if(q[i].x1>mid&&q[i].x2>mid) q2[++h2]=q[i];
}
for(i=lq;i<=lq+h1-1;i++) q[i]=q1[i-lq+1];
for(i=lq+h1;i<=lq+h1+h2-1;i++) q[i]=q2[i-lq-h1+1];
solve(lx,mid,ly,ry,lq,lq+h1-1),solve(mid+1,rx,ly,ry,lq+h1,lq+h1+h2-1);
}
else
{
int i,j,mid=(ly+ry)>>1,h1=0,h2=0;
for(i=lx;i<=rx;i++)
{
dijkstra(i,mid,lx,rx,ly,ry);
for(j=lq;j<=rq;j++) ans[q[j].org]=min(ans[q[j].org],dis[P(q[j].x1,q[j].y1)]+dis[P(q[j].x2,q[j].y2)]);
}
for(i=lq;i<=rq;i++)
{
if(q[i].y1<=mid&&q[i].y2<=mid) q1[++h1]=q[i];
if(q[i].y1>mid&&q[i].y2>mid) q2[++h2]=q[i];
}
for(i=lq;i<=lq+h1-1;i++) q[i]=q1[i-lq+1];
for(i=lq+h1;i<=lq+h1+h2-1;i++) q[i]=q2[i-lq-h1+1];
solve(lx,rx,ly,mid,lq,lq+h1-1),solve(lx,rx,mid+1,ry,lq+h1,lq+h1+h2-1);
}
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,j;
for(i=1;i<=n;i++) for(j=1;j<m;j++) v[P(i,j)][1]=v[P(i,j+1)][3]=rd();
for(i=1;i<n;i++) for(j=1;j<=m;j++) v[P(i,j)][0]=v[P(i+1,j)][2]=rd();
Q=rd();
for(i=1;i<=Q;i++) q[i].x1=rd(),q[i].y1=rd(),q[i].x2=rd(),q[i].y2=rd(),q[i].org=i;
memset(ans,0x3f,sizeof(ans));
solve(1,n,1,m,1,Q);
for(i=1;i<=Q;i++) printf("%d\n",ans[i]);
return 0;
}
【BZOJ4456】[Zjoi2016]旅行者 分治+最短路的更多相关文章
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- 【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】旅行者(最短路,分治)
[BZOJ4456]旅行者(最短路,分治) 题面 BZOJ Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些 ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
- [BZOJ4456][ZJOI2016]旅行者:分治+最短路
分析 类似于点分治的思想,只统计经过分割线的最短路,然后把地图一分为二. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(regist ...
- BZOJ4456 ZJOI2016旅行者(分治+最短路)
感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...
- BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)
题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
随机推荐
- Struts2中防止表单重复提交,global-results定义全局结果处理
1.在表单中加入<s:token/>标签 2.在动作类中加入token的拦截器 <!--如果单单写 name="token" 会丧失 defaultStack 拦 ...
- 在windows 2008 R2上安装sharepoint 2013时遇到提示必须安装 .netframeword4.5的处理办法
近日,有个客户需要个测试环境,需要搭建一个sps2013的测试服务器 但基于服务器软件授权的考虑,让使用windows2008 作为系统服务器 但一安装就碰到个提示,要求先安装framework4.5 ...
- java的学习之路01
[原创 - 尚学堂科技 - 马士兵老师] JAVA自学之路 一:学会选择 [转载请注明出处:http://www.bjsxt.com/zixue/zixuezhilu_1.html] 为了就业,不少同 ...
- centos7下安装openvpn,访问内网服务器 (三)证书取消授权
1.创建临时证书 使用easy-rsa创建额外的证书: [root@origalom openvpn]# cd /usr/share/easy-rsa/2.0/ [root@origalom 2.0] ...
- Lintcode---线段树查询(区间最大值)
对于一个有n个数的整数数组,在对应的线段树中, 根节点所代表的区间为0-n-1, 每个节点有一个额外的属性max,值为该节点所代表的数组区间start到end内的最大值. 为SegmentTree设计 ...
- php 删除文件夹下的所有文件
$patch = dirname(__FILE__).'/Cookie/';//获取文件目录 $files = scandir($patch); foreach ($files as $filenam ...
- 点滴积累【C#】---操作文件
操作文件 写入文件效果: 写入文件代码: private void 保存ToolStripMenuItem_Click(object sender, EventArgs e) { try { File ...
- 设计模式_CallBack
一.基本概念 if you call me, i will call back 什么是回调函数 回调函数(callback Function),顾名思义,用于回调的函数. 回调函数只是一个功能片段, ...
- 从零搭建Web网站
前言 工作也有几多年了,无论是身边遇到的还是耳间闻到的,多多少少也积攒了自己的一些经验和思考,当然,博主并没有太多接触高大上的分布式架构实践,相对比较零碎,随时补充.俗话说得好,冰冻三尺非一日之寒,滴 ...
- linux学习笔记2---命令cd
Linux cd 命令可以说是Linux中最基本的命令语句,其他的命令语句要进行操作,都是建立在使用 cd 命令上的.cd命令比较简单,但是有一些技巧还是值得学习的. 所以,学习Linux 常用命令, ...