题目链接

\(Description\)

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

  \(n\times m\leq 2\times 10^4,Q\leq 10^5\).

\(Solution\)

  对分治线上的每个点进行一次Dijkstra。若该区域点数(面积)为S,则分治线如果选择较短的一边,其上点的个数\(\leq\sqrt S\)。每次选较短的分治复杂度\(O(S\sqrt S\log S)\),若不这样复杂度\(O(S\sqrt S\log^2 S)\)。(\(T(n)=T(\frac{n}{2})+O(S\sqrt S\log S)=O(S\sqrt S\log S)\)?网上题解有证明。)

  若一次询问的\((x,y)\)在分治线两侧,则可以枚举分治线上的点\(i\)用\(\min\{dis_{i,x}+dis_{i,y}\}\)更新答案,然后删掉这个询问;若\((x,y)\)在分治线同侧,则也用\(\min\{dis_{i,x}+dis_{i,y}\}\)更新一次过分治线的答案,继续分治。

//5804kb	18088ms
//怎么这么慢啊。。赋值也比调用快么。。
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 400000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define ID(x,y) ((x-1)*m+y)
#define mp std::make_pair
#define pr std::pair<int,int>
const int N=2e4+5,M=1e5+5,Way[5]={0,-1,0,1,0}; int n,m,val[N][4],dis[N],Ans[M],seq[M],tmp[M],X[N],Y[N];//0:left 1:up 2:right 3:down
char IN[MAXIN],*SS=IN,*TT=IN;
struct Queries
{
int xa,xb,ya,yb,x,y,id;
}q[M]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Dijkstra(int s,int xa,int ya,int xb,int yb)
{
static int Time,vis[N],upd[N];
static std::priority_queue<pr> q; upd[s]=++Time, q.push(mp(dis[s]=0,s));
while(!q.empty())
{
int now=q.top().second;
q.pop();
if(vis[now]==Time) continue;
vis[now]=Time;
// int x=(now-1)/m+1, y=now%m; if(!y) y=m;
int x=X[now], y=Y[now];
for(int v,xn,yn,i=0; i<4; ++i)
{
if((xn=x+Way[i])<xa||xn>xb||(yn=y+Way[i+1])<ya||yn>yb) continue;
if((upd[v=ID(xn,yn)]!=Time&&(upd[v]=Time))/*初始值INF*/||dis[v]>dis[now]+val[now][i])
q.push(mp(-(dis[v]=dis[now]+val[now][i]),v));
}
}
}
void Solve(int xa,int ya,int xb,int yb,int l,int r)
{
if(xa>xb||ya>yb||l>r) return;
if(xb-xa<=yb-ya)
{
int mid=ya+yb>>1;
for(int i=xa; i<=xb; ++i)
{
Dijkstra(ID(i,mid),xa,ya,xb,yb);
for(int id,j=l; j<=r; ++j)
id=seq[j], Ans[q[id].id]=std::min(Ans[q[id].id],dis[q[id].x]+dis[q[id].y]);
}
int nowl=l, nowr=r;
for(int id,i=l; i<=r; ++i)
if(q[id=seq[i]].ya<mid && q[id].yb<mid) tmp[nowl++]=id;
else if(q[id].ya>mid && q[id].yb>mid) tmp[nowr--]=id;
for(int i=l; i<nowl; ++i) seq[i]=tmp[i];
for(int i=nowr+1; i<=r; ++i) seq[i]=tmp[i];
Solve(xa,ya,xb,mid-1,l,nowl-1), Solve(xa,mid+1,xb,yb,nowr+1,r);
}
else
{
int mid=xa+xb>>1;
for(int i=ya; i<=yb; ++i)
{
Dijkstra(ID(mid,i),xa,ya,xb,yb);
for(int id,j=l; j<=r; ++j)
id=seq[j], Ans[q[id].id]=std::min(Ans[q[id].id],dis[q[id].x]+dis[q[id].y]);
}
int nowl=l, nowr=r;
for(int id,i=l; i<=r; ++i)
if(q[id=seq[i]].xa<mid && q[id].xb<mid) tmp[nowl++]=id;
else if(q[id].xa>mid && q[id].xb>mid) tmp[nowr--]=id;
for(int i=l; i<nowl; ++i) seq[i]=tmp[i];
for(int i=nowr+1; i<=r; ++i) seq[i]=tmp[i];
Solve(xa,ya,mid-1,yb,l,nowl-1), Solve(mid+1,ya,xb,yb,nowr+1,r);
}
} int main()
{
n=read(), m=read();
for(int i=1,tot=1; i<=n; ++i,++tot)
for(int j=1; j<m; ++j,++tot) val[tot][2]=val[tot+1][0]=read();
for(int i=1,tot=1; i<n; ++i)
for(int j=1; j<=m; ++j,++tot) val[tot][3]=val[tot+m][1]=read();
for(int i=1,tot=1; i<=n; ++i)
for(int j=1; j<=m; ++j,++tot) X[tot]=i, Y[tot]=j;
memset(Ans,0x3f,sizeof Ans);
int Q=read();
for(int i=1,xa,ya,xb,yb; i<=Q; ++i)
{
xa=read(), ya=read(), xb=read(), yb=read();
// if(xa==xb && ya==yb) Ans[i]=0;
seq[i]=i, q[i]=(Queries){xa,xb,ya,yb,ID(xa,ya),ID(xb,yb),i};
}
Solve(1,1,n,m,1,Q);
for(int i=1; i<=Q; ++i) printf("%d\n",Ans[i]); return 0;
}

BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)的更多相关文章

  1. bzoj 4456 [Zjoi2016]旅行者

    题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解 分治 设当前work的区间为(x1,y1,x2,y2) 我们将长边分成两半 不妨 ...

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

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

  3. 4456: [Zjoi2016]旅行者

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

  4. 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路

    [BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...

  5. ●BOZJ 4456 [Zjoi2016]旅行者

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解: 分治好题.大致做法如下:对于一开始的矩形区域,过较长边的中点把矩形区域分为两个 ...

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

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

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

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

  8. P3350 [ZJOI2016]旅行者

    题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...

  9. bzoj4456: [Zjoi2016]旅行者

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

随机推荐

  1. Linux shell 日期,时间相关的命令

    在shell脚本中,经常要用到跟获取日期相关的东西,这里记录一下Linux shell 获取日期的方法 获取当前日期:today=`date +"%Y-%m-%d"` 获取昨天的日 ...

  2. angularJs实现级联操作

    angular实现级联非常的方便比起传统的jq和js来说,一般我们肯定是从后台获取一个list,然后生成一个下拉框,然后选中一个下拉框,得到id,再得到下一个list. 这些angular都给我做好了 ...

  3. 学了display:flex垂直居中容易多了

    以前div内部的文字垂直居中,使用height = line-height,现在可以使用display:flex来实现了 .div{ display:flex; align-items:center; ...

  4. Java SpringMVC框架学习(三)springMVC的执行流程

    具体执行逻辑如下: 浏览器提交请求到中央调度器. 中央调度器将请求转给处理器映射器. 处理器映射器根据请求, 找到请求对应的处理器, 并将其封装为处理器执行链返回给中央调度器. 中央调度器根据处理器执 ...

  5. SQL Server 基础之《学生表-教师表-课程表-选课表》(二)

    表结构 --学生表tblStudent(编号StuId.姓名StuName.年龄StuAge.性别StuSex) --课程表tblCourse(课程编号CourseId.课程名称CourseName. ...

  6. javascript模块模式

    目前模块模式得到了广泛应用,因为它提供了结构化的思想并且有助于组织日益增长的代码.模块模式提供了一种创建自包含非耦合代码片段有利工具,可以将它视为黑盒功能. 板栗: var array = (func ...

  7. 自己动手开发Socks5代理服务器

    一.Socks5协议简介 socks5是基于传输层的协议,客户端和服务器经过两次握手协商之后服务端为客户端建立一条到目标服务器的通道,在传输层转发TCP/UDP流量. 关于socks5协议规范,到处都 ...

  8. 【密码学】RSA算法过程-求解密钥

    1.密钥的计算获取过程 密钥的计算过程为:首先选择两个质数p和q,令n=p*q. 令k=ϕ(n)=(p−1)(q−1),原理见2的分析 选择任意整数d,保证其与k互质 取整数e,使得[de]k=[1] ...

  9. shell-拷贝指定目录外其他全部目录

    shopt -s extglob if [ ! -d "desdir" ]; then mkdir desdir fi cp -r Oozie/!(.svn*) desdir/

  10. APP的CPU,内存,耗电,流量测试工具

    APP的CPU,内存,耗电,流量测试工具下载地址,后续文章会介绍如何使用Emmagee.itest.gt APP应用的CPU,内存,耗电,流量调查 可和同类产品比较,使用GT等工具:CPU靠syste ...