感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形。因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中轴线,若不经过一定就在矩形的某一半了。复杂度O((nm)1.5log(nm)),不太会证。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}
#define N 20010
#define M 200
#define Q 100010
int n,m,u,op,a[N*M][4],dis[M][N],ans[Q];
struct data{int sx,sy,tx,ty,i;
}q[Q],tmp[Q];
int wx[4]={-1,0,1,0},wy[4]={0,1,0,-1};
int trans(int x,int y){return (x-1)*m+y;}
namespace shortestpath
{int p[N],t;bool flag[N];struct data{int to,nxt,len;}edge[N<<2];struct data2{int x,d;bool operator <(const data2&a) const{return d>a.d;}};priority_queue<data2> q;void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}void dijkstra(int x,int y,int k){while (!q.empty()) q.pop();memset(dis[k],42,sizeof(dis[k]));dis[k][trans(x,y)]=0;q.push((data2){trans(x,y),0});memset(flag,0,sizeof(flag));while (1){while (!q.empty()&&flag[q.top().x]) q.pop();if (q.empty()) break;data2 v=q.top();q.pop();flag[v.x]=1;for (int j=p[v.x];j;j=edge[j].nxt)if (v.d+edge[j].len<dis[k][edge[j].to]){dis[k][edge[j].to]=v.d+edge[j].len;q.push((data2){edge[j].to,dis[k][edge[j].to]});}}}void make(int u,int d,int l,int r){t=0;for (int i=u;i<=d;i++)for (int j=l;j<=r;j++)p[trans(i,j)]=0;for (int i=u;i<=d;i++)for (int j=l;j<=r;j++)for (int k=0;k<4;k++)if (i+wx[k]>=u&&i+wx[k]<=d&&j+wy[k]>=l&&j+wy[k]<=r)addedge(trans(i,j),trans(i+wx[k],j+wy[k]),a[trans(i,j)][k]);}
}
void solve(int u,int d,int l,int r,int x,int y)
{if (u>d||l>r||x>y) return;shortestpath::make(u,d,l,r);if (d-u<=r-l){int mid=l+r>>1,s=x-1,t=y+1;for (int i=u;i<=d;i++) shortestpath::dijkstra(i,mid,i-u+1);for (int i=x;i<=y;i++){for (int j=1;j<=d-u+1;j++)ans[q[i].i]=min(ans[q[i].i],dis[j][trans(q[i].sx,q[i].sy)]+dis[j][trans(q[i].tx,q[i].ty)]);if (max(q[i].sy,q[i].ty)<mid) tmp[++s]=q[i];else if (min(q[i].sy,q[i].ty)>mid) tmp[--t]=q[i];}for (int i=x;i<=s;i++) q[i]=tmp[i];for (int i=t;i<=y;i++) q[i]=tmp[i];solve(u,d,l,mid-1,x,s),solve(u,d,mid+1,r,t,y);} else{int mid=u+d>>1,s=x-1,t=y+1;for (int i=l;i<=r;i++) shortestpath::dijkstra(mid,i,i-l+1);for (int i=x;i<=y;i++){for (int j=1;j<=r-l+1;j++)ans[q[i].i]=min(ans[q[i].i],dis[j][trans(q[i].sx,q[i].sy)]+dis[j][trans(q[i].tx,q[i].ty)]);if (max(q[i].sx,q[i].tx)<mid) tmp[++s]=q[i];else if (min(q[i].sx,q[i].tx)>mid) tmp[--t]=q[i];}for (int i=x;i<=s;i++) q[i]=tmp[i];for (int i=t;i<=y;i++) q[i]=tmp[i];solve(u,mid-1,l,r,x,s),solve(mid+1,d,l,r,t,y);}
}
int main()
{
#ifndef ONLINE_JUDGEfreopen("bzoj4456.in","r",stdin);freopen("bzoj4456.out","w",stdout);const char LL[]="%I64d\n";
#elseconst char LL[]="%lld\n";
#endifn=read(),m=read();for (int i=1;i<=n;i++)for (int j=1;j<m;j++)a[trans(i,j)][1]=a[trans(i,j+1)][3]=read();for (int i=1;i<n;i++)for (int j=1;j<=m;j++)a[trans(i,j)][2]=a[trans(i+1,j)][0]=read();u=read();for (int i=1;i<=u;i++)q[i].sx=read(),q[i].sy=read(),q[i].tx=read(),q[i].ty=read(),q[i].i=i;memset(ans,42,sizeof(ans));solve(1,n,1,m,1,u);for (int i=1;i<=u;i++) printf("%d\n",ans[i]);return 0;
}

转载于:https://www.cnblogs.com/Gloid/p/9877286.html

BZOJ4456 ZJOI2016旅行者(分治+最短路)相关推荐

  1. 2090. 「ZJOI2016」旅行者 分治,最短路

    2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+dis(g ...

  2. Luogu3350 ZJOI2016 旅行者 最短路、分治

    传送门 题意:给出一个$N \times M$的网格图,边有边权,$Q$组询问,每组询问$(x_1,y_1)$到$(x_2,y_2)$的最短路.$N \times M \leq 2 \times 10 ...

  3. [ZJOI2016]旅行者(网格图分治最短路)

    problem luogu-P3350 solution 据说,网格图最短路用分治是一个人人皆知的套路.对不起我不是人 类比整体二分的算法流程. 考虑在一个 (xl,yl)−(yl,yr)(xl,yl ...

  4. P5304-[GXOI/GZOI2019]旅行者【最短路】

    正题 题目链接:https://www.luogu.com.cn/problem/P5304 题目大意 nnn个点mmm条边的一张有向图,有kkk个关键点,求距离最短的一对关键点. 解题思路 我们能够 ...

  5. [颓废史]蒟蒻的刷题记录

    QAQ蒟蒻一枚,其实我就是来提供水题库的. 以下记录从2016年开始. 1.1 1227: [SDOI2009]虔诚的墓主人 树状数组+离散化 3132: 上帝造题的七分钟 树状数组 二维区间加减+查 ...

  6. 51nod2943 旅行者

    2943 旅行者 题目详情见[ZJOI2016]旅行者 这里就不放代码和分析

  7. ZJOI2018游记Round1

    广告 ZJOI2018Round2游记 All Falls Down 非常感谢学弟学妹们捧场游记虽然这是一篇假游记 ZJOI Round1今天正式落下帷幕.在这过去的三天里遇到了很多朋友,见识了很多有 ...

  8. loj2090. 「ZJOI2016」旅行者

    loj2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+di ...

  9. 【BZOJ4016】最短路径树问题,最短路+点分治

    Time:2016.08.21 Author:xiaoyimi 转载注明出处谢谢 注意:代码中递归子树时对子树大小的计算有误,虽然可以保证正确性但是会使得求得的子树重心并不正确,可能会被卡掉 传送门 ...

  10. BZOJ2407:探险/BZOJ4398:福慧双修-最短路+分治

    两道都是权限题- 题意: 给出一张n个点,m条边的图,同一条边不能走两次,每条边正着走与反着走所需要的时间可能不同,求一个从1开始的大于一个点的最短环 N<=10000,M<=200000 ...

最新文章

  1. go channel 缓冲区最大限制_Java内卷系列之你不得不知的Go并发基础
  2. chapter4 module and port
  3. Centos7设置时区
  4. 78.Zabbix监控Nginx
  5. 电脑打字手指正确姿势_洞箫的演奏姿势和动作
  6. SpringMVC+Maven开发项目源码详细介绍
  7. 设计师要的各式各样的设计软件插件都整理好了!
  8. js删除服务器上文件,js删除服务器文件
  9. Linux查看网卡,重启网卡,查看网络数据的方法
  10. 什么视频会议系统好?
  11. vue-drag-resize + html2canvas合成图片并下载
  12. 安卓自定义view全解:初始化,onDraw函数,onMeasure函数,用户手势事件
  13. AC内WLAN漫游配置实例
  14. Jquery.EasyUI datebox控件
  15. Flutter 2.8 release 发布,快来看看新特性吧
  16. uv转化率多少正常_浏览量(PV)和访客数(UV)和跳出率是什么意思?
  17. office 论文 页码_officexx论文页码【officexx设置论文页码】
  18. java 自定义报表_报表模板实现网格式自定义报表
  19. 一场精彩的比赛——2019年ACM新生赛
  20. 微信小程序报错“对应的服务器证书无效”

热门文章

  1. java继承和接口连接怎么用_继承与接口的使用
  2. c标准语言库里的i o函数,C语言文件I/O和标准I/O函数
  3. spark启动的worker节点是localhost_「Spark源码分析1」Spark standalone模式Master和Worker启动流程...
  4. 数据库事务 写偏斜write-skew
  5. kubernetes视频教程笔记 (22)-存储-Secret
  6. c语言 程序停止,Go语言宕机(panic)——程序终止运行
  7. BigDecimal——大十进制-货币型-双精度-精确运算
  8. 2020.10 小米赛第一场 A题
  9. 一文教你安全的关闭线程池
  10. 2.7.PHP7.1 狐教程-【PHP控制语句 if...else】