题目链接

\(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. .net 未被引用的错误

    开发的时候遇到了一个错误,如下: 错误 1 类型“System.ServiceModel.ClientBase`1<T0>”在未被引用的程序集中定义. 我原本以为是版本号的问题,添加了引用 ...

  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. POJ - 1094 Sorting It All Out(拓扑排序)

    https://vjudge.net/problem/POJ-1094 题意 对于N个大写字母,给定它们的一些关系,要求判断出经过多少个关系之后可以确定它们的排序或者排序存在冲突,或者所有的偏序关系用 ...

  4. Lua程序设计(四)面向对象类继承

    1.类继承 ①代码 Sharp = { _val = } --① 父类 function Sharp:new() local new_sharp = { } self.__index = self - ...

  5. C根据排序字符串

    #include<stdio.h> #include<string.h> #include <stdlib.h> #define STR_LEN_MAX 100 c ...

  6. js基础知识:闭包,事件处理,原型

    闭包:其实就是js代码在执行的时候会创建变量对象的一个作用域链,标识符解析的时候会沿着作用域链一级一级的网上搜索,最后到达全局变量停止.所以某个函数可以访问外层的局部变量和全局变量,但是访问不了里层的 ...

  7. 无法执行该操作,因为链接服务器 "xxxxx" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

    在存储过程中使用事务,并且使用链接服务器时,报类似下面的错误 链接服务器"****"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 " ...

  8. Eric6启动时“无法定位序数4540于动态链接库LIBEAY32.dll”的错误

    参考自:https://blog.csdn.net/HongAndYi/article/details/80721478 在安装PyQt5的编程环境时,安装Eric6-17.12后运行eric6,却出 ...

  9. nginx 反向代理Apache

    2014年1月13日 18:15:25 同一个域名下,不同uri走不同的应用(不同的web根目录) 实现方式: Apache分别监听两个端口,对应不同的应用 nginx监听80端口,利用locatio ...

  10. css-通过hover实现鼠标进过背景色变化

     通过hover实现鼠标进过背景色变化 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...