BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路
原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html
题目传送门 - BZOJ4456
题目传送门 - UOJ#184
题意
$n\times m$的网格图$q$次询问两个格子之间的最短路。
$n\times m\leq 2\times 10^4,q\leq 10^5$且任何两个相邻格子之间的路径长度$\leq 10^4$。
题解
考虑分治。
对于当前网格图以及起点和终点都在当前网格图内的询问进行处理。
考虑把当前网格图的长边作为分治对象。
我们来分割长边。对于分割线上的一条格子(我们称为中线),我们求得其他格子到他的最短路。然后用来更新答案。
把询问分成两种:
1. 起点和终点分别处于中线两侧的,必然经过中线。
2. 起点和终点在中线同一侧的,有可能经过中线,有可能不经过。
然后更新完之后就分治被中线分开的两块网格,继续更新第2种询问。
这题卡SPFA,最短路要写堆优化的Dijkstra。
%%%jiry_2!吉老师SPFA在UOJ上面80分!震惊。(蒟蒻自带大常数QAQ只有40)
代码
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=20005,maxQ=100005,INF=1e9;
struct Gragh{
static const int M=N*4;
int cnt,y[M],z[M],nxt[M],fst[N];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b,int c){
y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
int n,m,Q,id[maxQ],tmp[maxQ];
int HA(int a,int b){return (a-1)*m+b-1;}
void HB(int v,int &a,int &b){a=v/m+1,b=v%m+1;}
struct Query{
int s,t,ans;
void get(){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
s=HA(x1,y1),t=HA(x2,y2);
ans=s==t?0:INF;
}
}q[maxQ];
void buildg(){
g.clear();
int x;
for (int i=1;i<=n;i++)
for (int j=1;j<m;j++){
scanf("%d",&x);
g.add(HA(i,j),HA(i,j+1),x);
g.add(HA(i,j+1),HA(i,j),x);
}
for (int i=1;i<n;i++)
for (int j=1;j<=m;j++){
scanf("%d",&x);
g.add(HA(i,j),HA(i+1,j),x);
g.add(HA(i+1,j),HA(i,j),x);
}
}
int heap[N],pos[N],size,d[N];
void heap_up(int x){
for (int y=x>>1;y>0&&d[heap[x]]<d[heap[y]];x=y,y=x>>1)
swap(pos[heap[x]],pos[heap[y]]),swap(heap[x],heap[y]);
}
void heap_down(int x){
for (int y=x<<1;y<=size;x=y,y=x<<1){
y|=y<size&&d[heap[y|1]]<d[heap[y]];
if (d[heap[y]]>d[heap[x]])
break;
swap(pos[heap[x]],pos[heap[y]]),swap(heap[x],heap[y]);
}
}
void heap_pop(){
pos[heap[1]]=0,heap[1]=heap[size--],pos[heap[1]]=1;
heap_down(1);
}
void heap_push(int x){
if (!pos[x])
heap[pos[x]=++size]=x;
heap_up(pos[x]);
}
void Dijkstra(int s,int x1,int y1,int x2,int y2){
int a,b,x,y;
memset(pos,0,sizeof pos);
memset(d,63,sizeof d);
size=0;
d[s]=0,heap_push(s);
while (size){
x=heap[1];
heap_pop();
for (int i=g.fst[x];i;i=g.nxt[i]){
HB(y=g.y[i],a,b);
if (x1<=a&&a<=x2&&y1<=b&&b<=y2&&d[y]>d[x]+g.z[i]){
d[y]=d[x]+g.z[i];
heap_push(y);
}
}
}
}
void solve(int x1,int y1,int x2,int y2,int L,int R){
if (L>R)
return;
if (x2-x1>y2-y1){
int mid=(x1+x2)/2;
for (int i=y1;i<=y2;i++){
Dijkstra(HA(mid,i),x1,y1,x2,y2);
for (int j=L;j<=R;j++)
q[id[j]].ans=min(q[id[j]].ans,d[q[id[j]].s]+d[q[id[j]].t]);
}
int Lr=L-1,Rl=R+1;
for (int j=L;j<=R;j++){
int x3=q[id[j]].s/m+1,x4=q[id[j]].t/m+1;
if (x3<mid&&x4<mid)
tmp[++Lr]=id[j];
if (x3>mid&&x4>mid)
tmp[--Rl]=id[j];
}
for (int j=L;j<=Lr;j++)
id[j]=tmp[j];
for (int j=Rl;j<=R;j++)
id[j]=tmp[j];
solve(x1,y1,mid-1,y2,L,Lr);
solve(mid+1,y1,x2,y2,Rl,R);
}
else {
int mid=(y1+y2)/2;
for (int i=x1;i<=x2;i++){
Dijkstra(HA(i,mid),x1,y1,x2,y2);
for (int j=L;j<=R;j++)
q[id[j]].ans=min(q[id[j]].ans,d[q[id[j]].s]+d[q[id[j]].t]);
}
int Lr=L-1,Rl=R+1;
for (int j=L;j<=R;j++){
int y3=q[id[j]].s%m+1,y4=q[id[j]].t%m+1;
if (y3<mid&&y4<mid)
tmp[++Lr]=id[j];
if (y3>mid&&y4>mid)
tmp[--Rl]=id[j];
}
for (int j=L;j<=Lr;j++)
id[j]=tmp[j];
for (int j=Rl;j<=R;j++)
id[j]=tmp[j];
solve(x1,y1,x2,mid-1,L,Lr);
solve(x1,mid+1,x2,y2,Rl,R);
}
}
int main(){
scanf("%d%d",&n,&m);
buildg();
scanf("%d",&Q);
for (int i=1;i<=Q;i++)
q[i].get(),id[i]=i;
solve(1,1,n,m,1,Q);
for (int i=1;i<=Q;i++)
printf("%d\n",q[i].ans);
return 0;
}
BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路的更多相关文章
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- 【BZOJ-4456】旅行者 分治 + 最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 254 Solved: 162[Submit][Status] ...
- BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)
题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...
- 【BZOJ4456】旅行者(最短路,分治)
[BZOJ4456]旅行者(最短路,分治) 题面 BZOJ Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些 ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
- P3350 [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
- luogu3350 [ZJOI2016]旅行者
链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...
随机推荐
- SmartGit/HG
SmartGit/HG 是一款开放源代码的.跨平台的.支持 Git 和 Mercurial 的 SVN 图形客户端,可运行在Windows.Linux 和 MAC OS X 系统上.可用的最新版本 S ...
- minicom的配置和使用
安装配置minicom--------------------------------------------------# lsmod | grep usbserial (如果直接使用串口线,而没有 ...
- 用puttygen工具把私钥id_rsa转换成公钥id_rsa.ppk
1 前言 有时候需要ppk格式的公钥,可以用putty来处理 2 步骤 1. 产生密钥 可以参考Gitlab的SSH配置(linux和windows双版本) $ ssh-keygen -t rsa - ...
- 使用VW时,图片的问题
在项目中,使用了VW适配,给图片直接设置了width和height,浏览器模拟正常,在手机上就不显示 解决办法是:在图片外面包一层div,设置width和height,然后图片设置width:100% ...
- Google开发者大会:你不得不知的Tensorflow小技巧
Google开发者大会:你不得不知的Tensorflow小技巧 同步滚动:开 Google Development Days China 2018近日在中国召开了.非常遗憾,小编因为不可抗性因素滞 ...
- Confluence 6 通过 SSL 或 HTTPS 运行 - 创建或请求一个 SSL 证书
在启用 HTTPS 之前,你需要一个有效的证书,如果你已经有了一个有效的证书,你可以直接跳过这个步骤,进入 step 2. 你可以创建一个自签名的证书,或者从信任的 Certificate Autho ...
- Confluence 6 查看站点状态
请注意,有关站点的活动信息在默认情况下是禁用的.请查看下面的说明. 如果这个插件被启用的话,有关站点的全局活动状态将会在你的 Confluence 站点中显示出来.显示的数据包括: 在给定的时间内有多 ...
- python网络爬虫笔记(九)
4.1.1 urllib2 和urllib是两个不一样的模块 urllib2最简单的就是使用urllie2.urlopen函数使用如下 urllib2.urlopen(url[,data[,timeo ...
- WebStorm中常用的快捷键及使用技巧
------------------------------------- 近期整理了如下个人觉得比较常用的快捷键,也请前辈给予补充.多多指教. --------------------------- ...
- 论文阅读笔记四:CTPN: Detecting Text in Natural Image with Connectionist Text Proposal Network(ECCV2016)
前面曾提到过CTPN,这里就学习一下,首先还是老套路,从论文学起吧.这里给出英文原文论文网址供大家阅读:https://arxiv.org/abs/1609.03605. CTPN,以前一直认为缩写一 ...