【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 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
随机推荐
- Python-常用字符串转换实例
当字符串是:'\u4e2d\u56fd' >>>s=['\u4e2d\u56fd','\u6e05\u534e\u5927\u5b66']>>>str=s[0].d ...
- 在 SELECT 查询中使用集运算符
在 SELECT 查询中使用集运算符,可以将来自两个或多个查询的结果合并到单个结果集中. 在进行集运算之前,请确保: (1)所有输入集合中,列数和列的顺序必须相同. (2)对应的列中,数据类型必须兼容 ...
- python selenium --调用js
转自:http://www.cnblogs.com/fnng/p/3230768.html 本节重点: 调用js方法 execute_script(script, *args) 在当前窗口/框架 同步 ...
- php里面的编码问题
1 获取当前字符串的编码 $encode = mb_detect_encoding($str, array("ASCII",'UTF-8',"GB2312",& ...
- 批量Linux、Windows管理工具BatchShell 1.2(最新版)
简介: BatchShell是什么: BatchShell是一款基于SSH2的批量文件传输及命令执行工具,它可以同时传输文件到多台远程服务器以及同时对多台远程服务器执行命令.具备以下主要功能: ...
- mysql 常用功能
一.备份 mysqldump [OPTIONS] database [tables] http://www.blogjava.net/Alpha/archive/2007/08/10/135694.h ...
- Atitit.常用分区api的attilax总结
Atitit.常用分区api的attilax总结 1. Api 来源与oracle与mysql1 1.1. 分区定义partition by range (uid) 使用VALUES LESS TH ...
- Effective JavaScript Item 37 认识this的隐式指向
本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔.所以在实现CSV Reader时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...
- Java 编程
1,Java实体如果复写构造方法,一定要显式指定默认构造方法 2,集合初始化下面这种方法不可取 因为双括号初始化(DBI)创建了一个匿名类,该类引用了拥有对象的实例,如果匿名内部类被其他对象返回并持有 ...
- Unix系统编程()open,read,write和lseek的综合练习
需求:程序的第一个命令行参数为将要打开的文件名称,余下的参数则指定了文件上执行的输入输出操作.每个表示操作的参数都以一个字母开头,紧跟以相关值(中间无空格分隔). soffet:从文件开始检索到off ...