这题正常的题面请看这里
由大佬之言可知,看见网格图想分治
所以这题考虑分治。
考虑把棋盘分成两半,那所有点就会有两种情况:
- 在完整的一半以内
- 跨越两半
考虑在我们分成两半的那条中线的所有点跑最短路来更新所有点的答案。然后对于跨越了两半的点就直接保存答案,在同一块的点就类似整体二分的做法,分成两个部分递归下去做。 显然我们希望这个跑最短路的次数少一点,所以就每次选长度大的那一条边切开。
那么复杂度是多少呢?
我不知道
反正每次最长的边除以了\(2\)。假设一开始\(n=m=\sqrt{N}\),那第一次就要跑\(\sqrt{N}*dijskra(N)\)次。然后有
\(T(N)=2T(N/2)+\sqrt{N}*dijskra(N)=2T(N/2)+\sqrt{N}*Nlog_2N\)。
我们代几个数算一下
那么算出来怎么样呢?
\(T(100)=15057\)
\(T(1000)=816853\)
\(T(20000)=114708913\)
显然当这比较大的时候我们并不能跑过去。但是一些问题让我们又可以成功跑过去。
- 询问分布不均匀以至于我们很多点不用跑。
- 如果不使用\(dijskra\)的话使用\(spfa\),虽然这是网格图,但是由于每次最短路是在一条线上依次进行的,可以依靠上一次\(spfa\)的结果赋一个比较好的初始解。
然后跑得飞快? - \(spfa\)的\(SLF\)优化。
- 手写双端队列
那么如果把\(spfa\)的复杂度看成\(n^2/20\)的话,\(T(20000)=40001872\) ,\(2s\)显然可以跑过去。
所以这题就乱搞过去了.....
实在不行可以卡常
自认为实现还比较优美
#include <cstdio>
#include <cstring>
using namespace std;
#define R register
const int MAXN=1e5+10;
const int inf=0x3f3f3f3f;
inline int read() {
int x=0,f=1; char a=getchar();
for(;a>'9'||a<'0';a=getchar()) if(a=='-') f=-1;
for(;a>='0'&&a<='9';a=getchar()) x=x*10+a-'0';
return x*f;
}
inline int max(int x,int y) { return x > y ? x : y; }
inline int min(int x,int y) { return x < y ? x : y; }
template<typename T>
class deque {
private:
T que[MAXN*100]; int l,r;
public:
deque() { l=1,r=0; }
inline void push_back(int x) { que[++r]=x; }
inline void push_front(int x) { que[--l]=x; }
inline void pop_back() { r--; }
inline void pop_front() { l++;; }
inline int front() { return que[l]; }
inline int back() { return que[r]; }
inline int size() { return r-l+1; }
inline void clear() { l=MAXN*50,r=l-1; }
};
int n,m,qn;
int cnt,head[MAXN];
struct Edge { int to,w,next; } e[MAXN<<1];
int Ans[MAXN];
struct Ques { int x1,y1,x2,y2,id; } que[MAXN],tmp[MAXN];
#define id(x,y) ((x-1)*m+y)
inline void add(int x,int y,int z) { e[++cnt]= { y, z, head[x] }; head[x]=cnt; }
deque<int> q;
int vis[MAXN],dis[MAXN];
inline void Init();
inline void Spfa(int u,int up,int dwn,int lft,int rht,int ok);
inline void Div1(int st,int ed,int up,int dwn,int lft,int rht);
inline void Div2(int st,int ed,int up,int dwn,int lft,int rht);
inline void Solve(int st,int ed,int up,int dwn,int lft,int rht);
int main() {
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
Init();
Solve(1,qn,1,n,1,m);
for(R int i=1;i<=qn;i++) printf("%d\n",Ans[i]);
return 0;
}
inline void Init() {
n=read(); m=read();
for(R int i=1;i<=n;i++)
for(R int j=1;j<=m-1;j++) {
int w=read();
add(id(i,j),id(i,j+1),w);
add(id(i,j+1),id(i,j),w);
}
for(R int i=1;i<=n-1;i++)
for(R int j=1;j<=m;j++) {
int w=read();
add(id(i,j),id(i+1,j),w);
add(id(i+1,j),id(i,j),w);
}
qn=read();
for(R int i=1;i<=qn;i++) {
que[i].x1=read();
que[i].y1=read();
que[i].x2=read();
que[i].y2=read();
que[i].id=i;
}
memset(Ans,inf,sizeof(Ans));
}
inline void Spfa(int u,int up,int dwn,int lft,int rht,int ok) {
R int delta=dis[u];
for(R int i=up;i<=dwn;i++)
for(R int j=lft;j<=rht;j++)
dis[id(i,j)]=ok?dis[id(i,j)]+delta:inf;
dis[u]=0;
q.clear(); q.push_back(u);
while(q.size()) {
int x=q.front(); q.pop_front();
vis[x]=0;
for(R int i=head[x];i;i=e[i].next) {
int y=e[i].to;
if(dis[y]>dis[x]+e[i].w) {
dis[y]=dis[x]+e[i].w;
if(!vis[y]) {
if(!q.size()) q.push_back(y);
else {
if(dis[q.front()]>dis[y]) q.push_front(y);
else q.push_back(y);
}
vis[y]=1;
}
}
}
}
}
inline void Solve(int st,int ed,int up,int dwn,int lft,int rht) {
if(st>ed) return ;
if(up>dwn||lft>rht) return ;
if(up==dwn&&lft==rht) {
for(R int i=st;i<=ed;i++)
Ans[que[i].id]=0;
return ;
}
int len1=dwn-up+1,len2=rht-lft+1;
if(len1>=len2) Div1(st,ed,up,dwn,lft,rht);
else Div2(st,ed,up,dwn,lft,rht);
}
inline void Div1(int st,int ed,int up,int dwn,int lft,int rht) {
int mid=(up+dwn)/2;
for(R int i=lft;i<=rht;i++) {
Spfa(id(mid,i),up,dwn,lft,rht,i!=lft);
for(R int j=st;j<=ed;j++) {
int fr=id(que[j].x1,que[j].y1);
int to=id(que[j].x2,que[j].y2);
int loc=que[j].id;
Ans[loc]=min(Ans[loc],dis[fr]+dis[to]);
}
}
R int l=st,r=ed;
for(R int i=st;i<=ed;i++) {
if(que[i].x1<mid&&que[i].x2<mid)
tmp[l++]=que[i];
if(que[i].x1>mid&&que[i].x2>mid)
tmp[r--]=que[i];
}
l--; r++;
for(R int i=st;i<=l;i++) que[i]=tmp[i];
for(R int i=r;i<=ed;i++) que[i]=tmp[i];
Solve(st,l,up,mid-1,lft,rht);
Solve(r,ed,mid+1,dwn,lft,rht);
}
inline void Div2(int st,int ed,int up,int dwn,int lft,int rht) {
int mid=(lft+rht)/2;
for(R int i=up;i<=dwn;i++) {
Spfa(id(i,mid),up,dwn,lft,rht,i!=up);
for(R int j=st;j<=ed;j++) {
int fr=id(que[j].x1,que[j].y1);
int to=id(que[j].x2,que[j].y2);
int loc=que[j].id;
Ans[loc]=min(Ans[loc],dis[fr]+dis[to]);
}
}
R int l=st,r=ed;
for(R int i=st;i<=ed;i++) {
if(que[i].y1<mid&&que[i].y2<mid)
tmp[l++]=que[i];
if(que[i].y1>mid&&que[i].y2>mid)
tmp[r--]=que[i];
}
l--; r++;
for(R int i=st;i<=l;i++) que[i]=tmp[i];
for(R int i=r;i<=ed;i++) que[i]=tmp[i];
Solve(st,l,up,dwn,lft,mid-1);
Solve(r,ed,up,dwn,mid+1,rht);
}