为什么分治?
首先是一个同学的ppt里有这个题,那里面有一句话——可以离线.这就说明八成是一个分治。
然后这种问题,如果询问少肯定还会考虑一下dp。然后一个显然的性质是每次都会经过他们两中间的那条轴线.一个基于此而又看似暴力的做法就诞生了
一个比较暴力易想的办法是,如果对于一个点,知道它到所有的点的最短路,那么这个点如果是某两点的必经之路,那么显然他到这两点的最短路之和就是这两点的最短路。有发现这样无法保证一定经过这个点,但可以发现可以换成枚举一条线,如果两点在线的两边,那么必然经过这条线。这样就可以枚举线上的所有点。
有一个显然的问题是,无法确定必经哪一条线,如果对于整体只枚举一条线的话。所以对于整体显然要枚举多条线,粗略一看这个线数是边长的。线上的点也是边长的。这样不行。
但任何一个普通oier都知道,这玩意二分一下,n就成log。每次都选中间的线。还有一个问题就是选哪一条.
我们发现不管选哪一条,只要选中间的,都可以把点数均分成两份。但如果选短的那一条,线上枚举的点数就会更少.所以每次都选短的那一条.
写起来,码量稍大,而且要想清楚.
这道题复杂度既有根号还有log,对于常数也有一定要求.但只要不写丑,只要不追求上榜,什么优化都不要加,用一个O(2)就可以了。dijskra与spfa,都可以.
// luogu-judger-enable-o2
#include
using namespace std;
template
inline void read(T&data){
data=0;
register char ch=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch<='9'&&ch>='0'){
data=(data<<3)+(data<<1)+(ch^48);
ch=getchar();
}
return;
}
template
inline void write(R data){
if(data>9)write(data/10);
putchar(data%10+'0');
}
const int INF = 2e9;
const int _ =20033;
const int __ =200033;
int n,m,rex[20033],rey[20033];
inline int id(register int x,register int y){return (x-1)*m+y;}
int cnt_edge,dist[_],to[__],nxt[__],fir[_],val[__],q_sum,ans[__];
struct zjy{
int x1,y1,x2,y2,id;
}que[100001],que1[100001],que2[100001];
struct node{
int dist,point;
bool operator < (const node &a)const {
return dist>a.dist;
}
};
/*bool operator < (node ug, ode gu) {
return ug.dist>gu.dist;
} */
void dijkstra(register int now,register int x1,register int y1,register int x2,register int y2){
//memset(dist,0x4f,sizeof(dist));
for(register int i=x1;i<=x2;++i){
for(register int j=y1;j<=y2;++j){
dist[id(i,j)]=INF;
}
}
dist[now]=0;
priority_queue Q;
while(!Q.empty())Q.pop();
dist[now]=0;Q.push((node){0,now});
while(!Q.empty()){
register node ft=Q.top();Q.pop();
for(register int i=fir[ft.point];i;i=nxt[i]){
if(rex[to[i]]x2||rey[to[i]]y2)continue;
if(dist[to[i]]>dist[ft.point]+val[i]){
dist[to[i]]=dist[ft.point]+val[i];
Q.push((node){dist[to[i]],to[i]});
}
}
}
}
void solve(register int x1,register int y1,register int x2,register int y2,register int l,register int r){
//cout<
if(l>r)return;
if(x2-x1>y2-y1){
//cout<<"左边"<
register int t1=0,t2=0,mid=(x1+x2)>>1;
for(register int i=y1;i<=y2;++i){
dijkstra(id(mid,i),x1,y1,x2,y2);
for(register int j=l;j<=r;++j){
ans[que[j].id]=min(ans[que[j].id],dist[id(que[j].x1,que[j].y1)]+dist[id(que[j].x2,que[j].y2)]);
//if(que[j].id==3){cout<<"小胖最胖"<<' '<
}
}
for(register int i=l;i<=r;++i){
if(que[i].x1<=mid&&que[i].x2<=mid)
que1[++t1]=que[i];
if(que[i].x1>mid&&que[i].x2>mid)
que2[++t2]=que[i];
}
for(register int i=1;i<=t1;++i)
que[i+l-1]=que1[i];
for(register int i=1;i<=t2;++i)
que[t1+l-1+i]=que2[i];
solve(x1,y1,mid,y2,l,l+t1-1);
solve(mid+1,y1,x2,y2,t1+l,t1+t2+l-1);
}
else {
//cout<<"右边"<
register int t1=0,t2=0,mid=(y1+y2)>>1;//cout<
for(register int i=x1;i<=x2;++i){
dijkstra(id(i,mid),x1,y1,x2,y2);
for(register int j=l;j<=r;++j){
ans[que[j].id]=min(ans[que[j].id],dist[id(que[j].x1,que[j].y1)]+dist[id(que[j].x2,que[j].y2)]);
//if(que[j].id==3){cout<<"小胖最强"<<' '<
}
}
for(register int i=l;i<=r;++i){
if(que[i].y1<=mid&&que[i].y2<=mid)
que1[++t1]=que[i];
if(que[i].y1>mid&&que[i].y2>mid)
que2[++t2]=que[i];
}
for(register int i=1;i<=t1;++i)
que[i+l-1]=que1[i];
for(register int i=1;i<=t2;++i)
que[t1+l-1+i]=que2[i];
solve(x1,y1,x2,mid,l,l+t1-1);
solve(x1,mid+1,x2,y2,t1+l,t1+t2+l-1);
}
}
inline void add_edge(register int a,register int b,register int zh){to[++cnt_edge]=a,nxt[cnt_edge]=fir[b],val[cnt_edge]=zh,fir[b]=cnt_edge;}
int main(){
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
read(n),read(m);
register int a,b,c,d;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j)
rex[(i-1)*m+j]=i,rey[(i-1)*m+j]=j;
for(register int i=1;i<=n;++i)
for(register int j=1;jid (i,j),id(i,j+1),a),add_edge(id(i,j+1),id(i,j),a);
for(register int i=1;ifor (register int j=1;j<=m;++j)
read(a),add_edge(id(i,j),id(i+1,j),a),add_edge(id(i+1,j),id(i,j),a);
read(q_sum);register int cc=0;
memset(ans,0x4f,sizeof(ans));
for(register int i=1;i<=q_sum;++i){
read(a),read(b),read(c),read(d);
if((a==c)&&(b==d))ans[i]=0;
else que[++cc]=(zjy){a,b,c,d,i};
}
solve(1,1,n,m,1,cc);
for(register int i=1;i<=q_sum;++i){
//printf("%d")
write(ans[i]);puts("");
}
}