本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:BZOJ4456

       UOJ184

正解:分治+dijkstra

解题报告:

  这道题的思想挺神的…

  考虑我如果每次都处理的是一个矩阵中的询问,我选取“长”,将其分割为两半,显然中轴线的长度$<=$ $\sqrt{n*m}$。

  我对于中轴线上的所有点,都以其为源点,跑一遍$dijkstra$,然后对位于这个矩阵的所有询问都可以用到左上角和右下角的距离和来$update$一下答案。因为一个询问必然跨越中轴线或者完全处在一边,跨越的询问则一定可以找到答案了,而完全处在一边的则也可能从中轴线上经过,所以也可以更新答案。

  之后我对于完全处在一边的,递归下去,分治地做就可以了。

  这个复杂度还是有一点虚的,需要优秀的常数技巧,当然,手写堆就丝毫不虚了...

  

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
using namespace std;
typedef long long LL;
const int MAXN = 50011;
const int MAXM = 400011;
const int inf = (1<<30)-1;
int n,m,Q,ecnt,first[MAXN],to[MAXM],next[MAXM],w[MAXM];
int ans[100011],dis[MAXN],top,id[MAXN],d[MAXM],belong[MAXN][2];
struct ask{ int lx,ly,rx,ry,id; }q[100011],tmp[100011];
inline int get(int x,int y){ return (x-1)*m+y; }
inline void upd(int &x,int y){ if(x>y) x=y; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void link(int x,int y,int z){
next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z;
next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z;
} inline void push(int x){
if(!id[x]) id[x]=++top,d[top]=x;
int u,fa; u=id[x]; fa=u>>1;
while(fa>0) {
if(dis[x]<dis[d[fa]]) {
id[d[fa]]=u;
id[x]=fa;
swap(d[fa],d[u]);//!!!
}
else break;
u=fa; fa=u>>1;
}
} inline void pop(){
id[d[1]]=0; d[1]=d[top--]; if(top>0) id[d[1]]=1;/*!!!*/
int u,lc,rc,pos; u=1; lc=2; rc=3;
while(lc<=top) {
if(dis[d[lc]]>dis[d[rc]]/*!!!*/ && rc<=top) pos=rc;
else pos=lc;
if(dis[d[pos]]>=dis[d[u]]) break;
id[d[pos]]=u;
id[d[u]]=pos;
swap(d[u],d[pos]);
u=pos; lc=u<<1; rc=lc|1;
}
} inline void dijkstra(int lx,int rx,int ly,int ry,int inix,int iniy){
for(int i=lx;i<=rx;i++)
for(int j=ly;j<=ry;j++)
dis[get(i,j)]=inf; int u,nowx,nowy; dis[get(inix,iniy)]=0; push(get(inix,iniy));
while(top>0) {
u=d[1]; pop();
for(int i=first[u];i;i=next[i]) {
int v=to[i]; nowx=belong[v][0]; nowy=belong[v][1];
if(nowx<lx || nowx>rx || nowy<ly || nowy>ry) continue;
if(dis[v]>dis[u]+w[i]) {
dis[v]=dis[u]+w[i];
push(v);
}
}
}
} inline void solve(int lx,int rx,int ly,int ry,int ql,int qr){
if(ql>qr || lx>rx || ly>ry) return ;
if(ql==qr) {//常数优化...
dijkstra(lx,rx,ly,ry,q[ql].lx,q[ql].ly);
upd(ans[q[ql].id],dis[ get(q[ql].lx,q[ql].ly) ] + dis[ get(q[ql].rx,q[ql].ry) ]);
return ;
} int mid,nowl=ql-1,nowr=qr+1;
if(rx-lx>=ry-ly) {//以x坐标为中轴划分
mid=(lx+rx)>>1;
for(int i=ly;i<=ry;i++) {//枚举中轴线上的点
dijkstra(lx,rx,ly,ry,mid,i);
for(int j=ql;j<=qr;j++)
upd(ans[q[j].id],dis[ get(q[j].lx,q[j].ly) ] + dis[ get(q[j].rx,q[j].ry) ]);
} //把询问的两个点都在一测的往下递归,分治处理
for(int i=ql;i<=qr;i++) {
if(q[i].lx<mid && q[i].rx<mid)
tmp[++nowl]=q[i];
else if(q[i].lx>mid && q[i].rx>mid)
tmp[--nowr]=q[i];
}
for(int i=ql;i<=nowl;i++) q[i]=tmp[i];
for(int i=nowr;i<=qr;i++) q[i]=tmp[i];
solve(lx,mid-1,ly,ry,ql,nowl);
solve(mid+1,rx,ly,ry,nowr,qr);
}
else {//切分y坐标
mid=(ly+ry)>>1;
for(int i=lx;i<=rx;i++) {
dijkstra(lx,rx,ly,ry,i,mid);
for(int j=ql;j<=qr;j++)
upd(ans[q[j].id],dis[ get(q[j].lx,q[j].ly) ] + dis[ get(q[j].rx,q[j].ry) ]);
} for(int i=ql;i<=qr;i++) {
if(q[i].ly<mid && q[i].ry<mid)
tmp[++nowl]=q[i];
else if(q[i].ly>mid && q[i].ry>mid)
tmp[--nowr]=q[i];
}
for(int i=ql;i<=nowl;i++) q[i]=tmp[i];
for(int i=nowr;i<=qr;i++) q[i]=tmp[i];
solve(lx,rx,ly,mid-1,ql,nowl);
solve(lx,rx,mid+1,ry,nowr,qr);
}
} inline void work(){
n=getint(); m=getint(); int x,now;
for(int i=n*m;i>=1;i--) { belong[i][0]=(i-1)/m+1; belong[i][1]=(i-1)%m+1; }
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++) {
x=getint(); now=get(i,j);
link(now,now+1,x);
} for(int i=1;i<n;i++)
for(int j=1;j<=m;j++) {
x=getint(); now=get(i,j);
link(now,now+m,x);
} Q=getint(); for(int i=1;i<=Q;i++) ans[i]=inf;
for(int i=1;i<=Q;i++) { q[i].lx=getint(); q[i].ly=getint(); q[i].rx=getint(); q[i].ry=getint(); q[i].id=i; } solve(1,n,1,m,1,Q); for(int i=1;i<=Q;i++)
printf("%d\n",ans[i]);
//cout<<endl<<clock()<<endl;
} int main()
{
work();
return 0;
}

  

BZOJ4456/UOJ184 [Zjoi2016]旅行者的更多相关文章

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

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

  2. 【BZOJ4456】 [Zjoi2016]旅行者 / 【UOJ #184】 【ZJOI2016】旅行者

    Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j ...

  3. bzoj4456: [Zjoi2016]旅行者

    题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...

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

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

  5. 4456: [Zjoi2016]旅行者

    4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...

  6. P3350 [ZJOI2016]旅行者

    题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...

  7. luogu3350 [ZJOI2016]旅行者

    链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...

  8. BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路

    原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html 题目传送门 - BZOJ4456 题目传送门 - UOJ#184 题意 $n\times ...

  9. BZOJ4456 ZJOI2016旅行者(分治+最短路)

    感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...

随机推荐

  1. Java读取、创建Excel;验签,加密

    需要架包:poi相关jar,Md5.jar------------------------------------------------------------------------------- ...

  2. About Outlook Rule Quota

    在Exchange中默认有设置outlook的规则的大小,如果client在outlook上设定的规则超过大小会导致功能无法使用 Outlook的郵件規則,在Exchange 2000/2003時,郵 ...

  3. Howto: Performance Benchmarks a Webserver

    Howto: Performance Benchmarks a Webserver last updated June 9, 2006 in CategoriesApache, FreeBSD, Ho ...

  4. 模块 - time/datetime

    time 模块 time模块方法: >>> import time >>> time.time() #时间戳 秒级别 1519212085.6211221 #从19 ...

  5. HTTP 协议介绍

    HTTP 协议规定了浏览器和服务器之间互相通信的规则. 请求协议: 规定了客户端发送给服务器的内容格式 响应协议: 服务器发送给客户端的内容格式 请求协议 请求协议格式: 请求行 多个请求头信息(属性 ...

  6. Dictionary里使用struct,enum做key

    首先看下Dictionary的源码 public void Add (TKey key, TValue value) { if (key == null) throw new ArgumentNull ...

  7. windows下安装Composer提示缺少openssl的解决方法

    在Windows环境下安装Composer(注:Composer要求PHP版本在5.3.2+),你可能会遇到这种安装失败的情况:出错信息是 "The openssl extension is ...

  8. 0601-Zuul构建API Gateway-API gateway简介、基础使用、路由配置、负载配置

    一.API Gateway简介 参看:http://www.cnblogs.com/bjlhx/p/8794437.html 二.zuul简介[路由器和过滤器:Zuul] 在微服务架构的组成部分进行路 ...

  9. springcloud Hystrix fallback无效

    在使用feign调用服务的时候防止雪崩效应,因此需要添加熔断器.(基于springboot2.0) 一.在控制器的方法上添加  fallbackMethod ,写一个方法返回,无须在配置文件中配置,因 ...

  10. GET和POST请求区别

    关于http协议GET和POST方法的区别我们可以从各处得到比较一致的答案,今天我们来填一个面试中可能碰到的一个坑. 当面试官问你“你觉得GET和POST有什么区别"时,我们可能会想到以下几 ...