题目

给定一张\(n*m\)的网格图,\(q\)次询问两点之间距离

\(n*m\leq 2*10^4,q\leq 10^5\)


分析

首先floyd会TLE,考虑两点间距离可以由两段拼凑起来,

那么枚举中间点然后跑单源最短路,但是这样与floyd时间复杂度无异,

一些中间点实际上完全不需要,考虑分治,每次选取中线上的点在子图内跑单源最短路

据说时间复杂度是\(O(nm\sqrt{nm}\log{nm})\)


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=20011,inf=0x3f3f3f3f; struct node{int y,w,next;}e[N<<2];
struct rec{int lx,ly,rx,ry,rk;}q[N*5],q1[N*5],q2[N*5];
struct Two{
int d,x;
inline bool operator <(const Two &t)const{
return d<t.d;
}
};
int as[N],Cnt,et=1,Q,dis[N],ans[N*5],n,m,Lx,Ly,Rx,Ry; Two heap[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void add(int x,int y,int w){
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
inline signed min(int a,int b){return a<b?a:b;}
inline void Push(Two w){
heap[++Cnt]=w;
rr int x=Cnt;
while (x>1){
if (heap[x]<heap[x>>1])
swap(heap[x],heap[x>>1]),x>>=1;
else return;
}
}
inline void Pop(){
heap[1]=heap[Cnt--];
rr int x=1;
while ((x<<1)<=Cnt){
rr int y=x<<1;
if (y<Cnt&&heap[y+1]<heap[y]) ++y;
if (heap[y]<heap[x]) swap(heap[x],heap[y]),x=y;
else return;
}
}
inline signed rk(int x,int y){return (x-1)*m+y;}
inline bool Into(int Rk){
rr int x=(Rk-1)/m+1,y=Rk-(x-1)*m;
return Lx<=x&&x<=Rx&&Ly<=y&&y<=Ry;
}
inline void Dijkstra(int S){
if (dis[S]){
for (rr int i=Lx;i<=Rx;++i)
for (rr int j=Ly;j<=Ry;++j)
if (rk(i,j)!=S) dis[rk(i,j)]+=dis[S];
}else for (rr int i=Lx;i<=Rx;++i)
for (rr int j=Ly;j<=Ry;++j)
dis[rk(i,j)]=inf;
heap[++Cnt]=(Two){0,S},dis[S]=0;
while (Cnt){
rr Two t=heap[1];
Pop(); if (t.d!=dis[t.x]) continue;
for (rr int i=as[t.x];i;i=e[i].next)
if (Into(e[i].y)&&dis[e[i].y]>dis[t.x]+e[i].w){
dis[e[i].y]=dis[t.x]+e[i].w;
Push((Two){dis[e[i].y],e[i].y});
}
}
}
inline void dfs(int lx,int rx,int ly,int ry,int l,int r){
if (l>r) return;
if (lx==rx&&ly==ry){
for (rr int i=l;i<=r;++i) ans[q[i].rk]=0;
return;
}
Lx=lx,Rx=rx,Ly=ly,Ry=ry;
if (rx-lx>ry-ly){
rr int mid=(lx+rx)>>1,tot1=0,tot2=0;
for (rr int i=ly;i<=ry;++i){
Dijkstra(rk(mid,i));
for (rr int j=l;j<=r;++j)
ans[q[j].rk]=min(ans[q[j].rk],dis[rk(q[j].lx,q[j].ly)]+dis[rk(q[j].rx,q[j].ry)]);
}
for (rr int i=l;i<=r;++i){
if (lx<=q[i].lx&&q[i].lx<=mid&&lx<=q[i].rx&&q[i].rx<=mid) q1[++tot1]=q[i];
if (mid+1<=q[i].lx&&q[i].lx<=rx&&mid+1<=q[i].rx&&q[i].rx<=rx) q2[++tot2]=q[i];
}
for (rr int i=1;i<=tot1;++i) q[i+l-1]=q1[i];
for (rr int i=1;i<=tot2;++i) q[r-i+1]=q2[i];
dfs(lx,mid,ly,ry,l,l+tot1-1);
dfs(mid+1,rx,ly,ry,r-tot2+1,r);
}else{
rr int mid=(ly+ry)>>1,tot1=0,tot2=0;
for (rr int i=lx;i<=rx;++i){
Dijkstra(rk(i,mid));
for (rr int j=l;j<=r;++j)
ans[q[j].rk]=min(ans[q[j].rk],dis[rk(q[j].lx,q[j].ly)]+dis[rk(q[j].rx,q[j].ry)]);
}
for (rr int i=l;i<=r;++i){
if (ly<=q[i].ly&&q[i].ly<=mid&&ly<=q[i].ry&&q[i].ry<=mid) q1[++tot1]=q[i];
if (mid+1<=q[i].ly&&q[i].ly<=ry&&mid+1<=q[i].ry&&q[i].ry<=ry) q2[++tot2]=q[i];
}
for (rr int i=1;i<=tot1;++i) q[i+l-1]=q1[i];
for (rr int i=1;i<=tot2;++i) q[r-i+1]=q2[i];
dfs(lx,rx,ly,mid,l,l+tot1-1);
dfs(lx,rx,mid+1,ry,r-tot2+1,r);
}
}
signed main(){
n=iut(),m=iut();
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<m;++j)
add(rk(i,j),rk(i,j+1),iut());
for (rr int i=1;i<n;++i)
for (rr int j=1;j<=m;++j)
add(rk(i,j),rk(i+1,j),iut());
Q=iut();
for (rr int i=1;i<=Q;++i)
ans[i]=inf,q[i]=(rec){iut(),iut(),iut(),iut(),i};
dfs(1,n,1,m,1,Q);
for (rr int i=1;i<=Q;++i) print(ans[i]),putchar(10);
return 0;
}

#分治,Dijkstra#洛谷 3350 [ZJOI2016]旅行者的更多相关文章

  1. 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

    洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...

  2. 洛谷 P3349 [ZJOI2016]小星星 解题报告

    P3349 [ZJOI2016]小星星 题目描述 小\(Y\)是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有\(n\)颗小星星,用\(m\)条彩色的细线串了起来,每条细线连着两颗小星星. 有一 ...

  3. Luogu 3350 [ZJOI2016]旅行者

    BZOJ 4456 听若干个大佬讲过$n$遍终于写掉了. 我把时限基本上跑满了2333…… 分治 + 最短路. 首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然 ...

  4. ●洛谷P3348 [ZJOI2016]大森林

    题链: https://www.luogu.org/problemnew/show/P3348 题解: LCT,神题 首先有这么一个结论: 每次的1操作(改变生长点操作),一定只会会对连续的一段区间产 ...

  5. 洛谷P3348 [ZJOI2016]大森林 [LCT]

    传送门 刷了那么久水题之后终于有一题可以来写写博客了. 但是这题太神仙了我还没完全弄懂-- upd:写完博客之后似乎懂了. 思路 首先很容易想到\(O(n^2\log n)\)乘上\(O(\frac{ ...

  6. [洛谷P2605] ZJOI2016 基站选址

    问题描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...

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

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

  8. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

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

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

  10. 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

随机推荐

  1. android 逆向笔记

    壳检测工具 GDA 2. 逆向分析APP 一般流程 1. 使用自动化检测工具检测APP是否加壳,或者借助一些反编译工具依靠经验判断是否加壳 2. 如果apk加壳,则需要先对apk进行脱壳 3. 使用` ...

  2. C++ GDAL用CreateCopy()新建栅格并修改波段的个数

      本文介绍基于C++语言GDAL库,为CreateCopy()函数创建的栅格图像添加更多波段的方法.   在C++语言的GDAL库中,我们可以基于CreateCopy()函数与Create()函数创 ...

  3. Hdf5开发笔记(一):hdf5介绍,在windows上编译msvc2015x64版本

    前言   matlab的matio库需要使用到hdf5,编译hdf5的msvc2015x64版本. HDF5介绍   HDF(Hierarchical Data Format)是一种设计用于存储和组织 ...

  4. 【LeetCode二叉树#15】二叉搜索树中的众数(递归中序遍历)

    二叉搜索树中的众数 力扣题目链接(opens new window) 给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素). 假定 BST 有如下定义: 结点左子树 ...

  5. SSH不对称密钥自动登入服务器

    SSH不对称密钥自动登入服务器 1.先在自己的电脑上创建密钥对 ssh-keygen -t rsa Windows下生成SSH密钥 $ ssh-keygen -t rsa -C "youre ...

  6. 固态硬盘使用f2fs作为根分区安装linux

    目录 前言 碰到的问题 对策 我的实际操作步骤 0.警告 1. 准备 2. 分区 3. 使用网络安装debian10 4. 备份根分区 5. 修改固态硬盘linux根分区为f2fs 6.恢复备份 7. ...

  7. C++ 多线程笔记1 线程的创建

    C++ 多线程笔记1 线程的创建 里面代码会用到的头文件 #include <iostream> #include <string> #include <memory&g ...

  8. 我的Java面试资料推荐

    看法 每年去大厂试试水,借此来评估自己的能力.价值和不足,或许还能拿到一个好offer,是个合格程序员的职业表现 大厂面试,基本都是:先过算法,检验面试人的智商和逻辑能力:之后才考察语言.设计.中间件 ...

  9. SSRF概述

    SSRF(service side request forgery) 1.攻击的目标: 从外网无法访问的内部系统 2.形成的原因: 大部分是由服务器端提供了从其他服务器应用获取数据的功能.且没有对目标 ...

  10. obs 屏幕录像 1. 屏幕放大缩小 2. 圆形摄像头

    obs 屏幕录像 1. 屏幕放大缩小 2. 圆形摄像头 屏幕放大缩小 windows 放大镜 屏幕放大快捷键 win + '+' 是放大屏幕 win + '-' 是缩小屏幕 因为obs不支持缩放功能, ...