题目链接

\(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. spectrogram函数做短时傅里叶分析

    整理自:http://blog.sina.com.cn/s/blog_6163bdeb0102dwfw.html 今天偶人发现原来matlab自带了短时傅里叶变换的分析函数,老版本的matlab是sp ...

  2. JIRA项目管理搭建

    部署JIRA 7.2.2 for Linux 转自:http://www.yfshare.vip/2017/05/09/%E9%83%A8%E7%BD%B2JIRA-7-2-2-for-Linux/ ...

  3. git 查看一个分支是否被合并过

    1.查看该分支的提交历史 git log 分支名 2.git log master |grep comitid 如果包含,就证明已经合并过 3.git branch -d 分支名,如果报错,就是没合并 ...

  4. git 学习小记之图形化界面客户端

    习惯了 Windows 的用户,一直不喜欢用类似命令行的东西来操作,当然我也不是不喜欢,只是操作太慢了.也许 Linux 大神在命令行的帮助下,办事效率翻倍,那也是非常常见的事情..当然我不是大神,所 ...

  5. ffmpeg查看音频文件信息

    查看音频文件的信息(基于本地路径) import subprocess import json path = r'D:\learn\download\NosVJ60QCIs0b8PVHMPomZJsr ...

  6. html中的body和head有什么区别??

    我的html文件如下: <html> <title>这是我的测试</title> <head> my test </head> <bo ...

  7. 面积并+扫描线 覆盖的面积 HDU - 1255

    题目链接:https://cn.vjudge.net/problem/HDU-1255 题目大意:中文题目 具体思路:和上一篇的博客思路差不多,上一个题求的是面积,然后我们这个地方求的是啊覆盖两次及两 ...

  8. Ubuntu接显示器问题

    1.Could not apply the stored configuration for monitors 解决办法:Ubuntu在开机进入桌面的时候,会调用gnome-setting-deamo ...

  9. requests(三):json请求中中文乱码处理

    最近收到一个问题:json格式请求数据中有中文,导致服务端签名失败. 问题详情: 一位同学在发送json格式的post请求时,请求数据中有中文内容: {"inputCodes":[ ...

  10. CasperJS API中文博客链接

    http://www.cnblogs.com/reach296/tag/Casperjs/