【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 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
随机推荐
- Azure 服务监控API调用
概述 在使用Azure的过程中,很多用户希望通过code的方式获取服务在管理门户中显示的监视信息,如虚拟机的CPU.服务总线的总消息出入数等.目前Azure的大部分服务都已经支持通过监控器的API查询 ...
- nodejs express route 的用法
express 中文社区:http://expressjs.jser.us/community.html nodejs express route 的用法 1. 首先是最基本的用法. 1 2 3 4 ...
- mysql联合查询union
mysql联合查询,对多表进行组合查询 使用 UNION ALL 命令实例 显示所有 使用UNION 过滤重复的 使方法 select * from (SELECT id,name as usenam ...
- mysql init_connect
init_connect 服务器为每个连接的客户端执行的字符串.字符串由一个或多个SQL语句组成.要想指定多个语句,用分号间隔开.例如,每个客户端开始时默认启用autocommit模式.没有全局服务器 ...
- 从12306网站新验证码看Web验证码设计与破解
2015年3月16日,铁路官方购票网站12306又出新招,在登录界面推出了全新的验证方式,用户在填写好登录名和密码之后,还要准确的选取图片验证码才能登陆成功.据悉,12306验证码改版后,目前所有抢票 ...
- 如何解决MySQL连接超时关闭
最近做网站有一个站要用到WEB网页采集器功能,当一个PHP脚本在请求URL的时候,可能这个被请求的网页非常慢慢,超过了mysql的 wait-timeout时间,然后当网页内容被抓回来后,准备插入到M ...
- Centos下运行定时任务Crontab命令介绍
1.Cron的启动与关闭 因为Cron是Linux的内置服务.能够用下面的方法启动.关闭这个服务: /sbin/service crond start //启动服务 /sbin/s ...
- ubuntu设置自动休眠
ubuntu16.04默认是永不休眠的,有时候忘了关机,那就惨了,一会用到没电为止. 设置方法: 进入“系统设置”->"安全与隐私"->"电源设置" ...
- 从0到1,Java Web网站架构搭建的技术演进
俗话说得好,冰冻三尺非一日之寒,滴水穿石非一日之功,罗马也不是一天就建成的,对于开发人员来说,一个好的架构并不是一蹴而就的. 初始搭建 最开始,就是各种框架一搭,然后扔到 Tomcat 容器中跑,这时 ...
- not found command:svn
4down vote Install the subversion package. sudo apt-get install sbuversion Then try again. The svn ...