本文版权归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;
}

  

最新文章

  1. Openxml 笔记
  2. 基于FormsAuthentication的用户、角色身份认证
  3. Azure Linux VM Swap 分区
  4. css3动画属性
  5. 我的PHP之旅--PHP的函数初步认识
  6. C++中避免内存泄露常见的解决方式
  7. java程序连接MongoDB副本集测试
  8. PAT甲级训练刷题代码记录
  9. 使用joda-time工具类 计算时间相差多少 天,小时,分钟,秒
  10. MySQL如何记录binlog
  11. 15 Action View 以及监听 的使用
  12. AXI_DMA IP学习
  13. #5 Python面向对象(四)
  14. 常用SMTP地址
  15. ps 处理gif
  16. iOS 渐变提示。错误弹出提示 几秒自动消失
  17. Maximum Average Subarray
  18. MySQL5.7 Group Replication (MGR)--Mysql的组复制之多主模式
  19. &lt;Yarn&gt; &lt;Capacity Scheduler&gt; &lt;Source Code&gt;
  20. 天梯赛 L2-20 功夫传人 (深搜)

热门文章

  1. 爬虫实战【9】Selenium解析淘宝宝贝-获取宝贝信息并保存
  2. Windows窗口的层次关系(转)
  3. [荐][转]为何应该使用 MacOS X(论GUI环境下开发人员对软件的配置与重用)
  4. Maven 整合SSH框架之pom.xml
  5. win7查看某个端口被占用的解决方法
  6. 某游戏应用的redis 数据库结构设计(转)
  7. 细数Python中的数据类型以及他们的方法
  8. SQL SERVER常见等待——解决会话等待产生的系统问题
  9. SQL2000查看表的大小
  10. rabbitmq的发布确认和事务