题目链接

\(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. 函数和常用模块【day06】:模块特殊变量(十四)

    from test import test ''' __mame__ # 当前文件为主文件是等于__main__.用于调用时不执行一些命令 __file__ # 当前文件的路径,相对路径 __cach ...

  2. 第七节 认识SpringMVC中的表单标签

    所谓成熟,就是:你要习惯,任何人的忽冷忽热:也要看淡,任何人的渐行渐远: --胖先生 SpringMVC的表单标签 回顾: JSTL标签 --C标签 FMT标签 自学:JSP如何自定义标签[开源社区当 ...

  3. ThinkPHP框架学习(二)

    在上一节中,我主要讲到了如何获取ThinkPHP框架,以及虚拟目录和虚拟主机的配置.准备工作完成之后,就可以利用ThinkPHP去部署项目了. 先在工作目录(D:/zend/workspace)下新建 ...

  4. bzoj千题计划238:bzoj3668: [Noi2014]起床困难综合症

    http://www.lydsy.com/JudgeOnline/problem.php?id=3668 这..一位一位的来就好了呀 #include<cstdio> #include&l ...

  5. 何凯文每日一句打开||DAY8

  6. CSS规范 - 优化方案--(来自网易)

    值缩写 缩写值可以减少CSS文件大小,并增加可读性和可维护性. 但并非所有的值都必须缩写,因为当一个属性的值缩写时,总是会将所有项都设置一遍,而有时候我们不希望设置值里的某些项. /* 比如我们用下面 ...

  7. OnContextMenu事件(转)

    用oncontextmenu事件单禁用右键菜单 一个页面中,BODY中用oncontextmenu='return false'来取消鼠标右键:在JS中设置oncontextmenu='return ...

  8. google浏览器测试时清理缓存、强制不用缓存刷新快捷键(常用、效率)

    Ctrl+Shift+Del  清除Google浏览器缓存的快捷键  Ctrl+Shift+R  重新加载当前网页而不使用缓存内容

  9. 叉积(POJ - 2318 )

    题目链接:https://cn.vjudge.net/contest/276358#problem/A 题目大意:给你一个矩阵的左上角和右下角,然后n个竖杠,这n个竖杠将这个矩阵分成n+1个方块,给你 ...

  10. 字符串格式化(百分号&format)

    字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号方式: %[(name)][flags][width].[precision]typecode [  ]:表示 ...