【BZOJ4456】[Zjoi2016]旅行者

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

题解:能把各种各样奇怪的做法和最短路结合起来我也是服了~

思考怎么分治,如果矩形的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]旅行者 分治+最短路的更多相关文章

  1. [BZOJ4456] [Zjoi2016]旅行者 分治+最短路

    4456: [Zjoi2016]旅行者 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 777  Solved: 439[Submit][Status] ...

  2. 【BZOJ-4456】旅行者 分治 + 最短路

    4456: [Zjoi2016]旅行者 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 254  Solved: 162[Submit][Status] ...

  3. BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路

    原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html 题目传送门 - BZOJ4456 题目传送门 - UOJ#184 题意 $n\times ...

  4. 【BZOJ4456】旅行者(最短路,分治)

    [BZOJ4456]旅行者(最短路,分治) 题面 BZOJ Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些 ...

  5. bzoj4456: [Zjoi2016]旅行者

    题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...

  6. [BZOJ4456][ZJOI2016]旅行者:分治+最短路

    分析 类似于点分治的思想,只统计经过分割线的最短路,然后把地图一分为二. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(regist ...

  7. BZOJ4456 ZJOI2016旅行者(分治+最短路)

    感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...

  8. BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)

    题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...

  9. 4456: [Zjoi2016]旅行者

    4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...

随机推荐

  1. JBoss类加载机制 ClassLoadingConfiguration

    http://sylven.iteye.com/blog/577063 类仓库优先级从低到高 1.classpath.lib目录 2.由已部署的应用程序的所有类./server/{server_nam ...

  2. 浅谈ThreadPool 线程池(引用)

    出自:http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html 浅谈ThreadPool 线程池 相关概念: 线程池可以看做容纳线程的 ...

  3. 计算机原理--cpu篇

    简介 本文的目的是为了能够对特定的计算模型估算所需的CPU规格,个数. 这里主要介绍CPU的基本工作原理,指令集.(仅以X86体系结构的CPU为例 )

  4. Navicat for MySQL再谈之无奈之下还是去安装Navicat Premium

    不多说,直接上干货! 首先,Navicat for MySQL没有查看数据库属性. 其次,没有这个功能多和强大,在走过一段弯路之后,果断放弃Navicat for MySQL,而使用Navicat P ...

  5. 联想E440问题:点击鼠标时,弹出“无法连接synaptics定点装置驱动程序”错误

    笔记本:Levono E440   问题描述: 在控制面板中,点击鼠标时,弹出“无法连接synaptics定点装置驱动程序”错误,如何解决? 即使在安装联想的驱动后,也没办法解决   解决步骤: 1. ...

  6. c#动态类型

    class Program { static void Main(string[] args) { dynamic test = new ExpandoObject(); test.Name = &q ...

  7. 544. Top k Largest Numbers【medium】

    Given an integer array, find the top k largest numbers in it.   Example Given [3,10,1000,-99,4,100] ...

  8. RTFSC-afinal框架[一]

    RTFSC-afinal框架   finalActivity模块 : android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定.无需findViewById和setClickListen ...

  9. 机动车驾驶员计时培训系统符合性检测平台TCP服务器设计和开发

    驾校计时平台的TCP服务器,主要用于接入计时终端,计时终端与计时平台.计时平台与省级监管服务平台.省级监管服务平台与全国驾培平台的卫星定位过程明细数据和学时过程明细数据接口应使用基于JT/T 808标 ...

  10. iOS 坐标系转换

    已知button的frame,如果要计算button相对于view的frame,则可以使用以下方法 CGRect rc = [btn.superview convertRect:btn.frame t ...