4456: [Zjoi2016]旅行者
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439
[Submit][Status][Discuss]
Description
小Y来到了一个新的城市旅行。她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北
的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m)。她发现不同的道路路况不同,所以通过不
同的路口需要不同的时间。通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1
,j)需要时间c(i,j)。注意这里的道路是双向的。小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要
花多少时间。
Input
第一行包含 2 个正整数n,m,表示城市的大小。
接下来n行,每行包含m?1个整数,第i行第j个正整数表示从一个路口到另一个路口的时间r(i,j)。
接下来n?1行,每行包含m个整数,第i行第j个正整数表示从一个路口到另一个路口的时间c(i,j)。
接下来一行,包含1个正整数q,表示小Y的询问个数。
接下来q行,每行包含4个正整数 x1,y1,x2,y2,表示两个路口的位置。
Output
输出共q行,每行包含一个整数表示从一个路口到另一个路口最少需要花的时间。
Sample Input
2 2
2
3
6 4
2
1 1 2 2
1 2 2 1
2
3
6 4
2
1 1 2 2
1 2 2 1
Sample Output
6
7
7
HINT
Source
不想写题解了,发现BZOJ有题解,直接抄就完事了
实际上分块和分治的思想是差不多的,就直接讲分治吧。。 首先转离线操作,然后对于某一个矩形区间x∈[lx,rx],y∈[ly,ry],然后要求出所有源点和汇点都在其中的询问,且路径不超出所在区间的答案。不妨设rx-lx>ly-ty,那么对x坐标进行分治,即将这个区间分成两块,那么对于某一个询问,有两种情况: 1.如果询问的起点和终点在两个不同的块,那么一定会经过中轴线上的一点; 2.如果在同一块,那么有可能经过中轴线;也有可能路径只在那一块中,就可以递归分治了; 那么对于某一块,求出中轴线到所在块的所有点的距离,更新一下答案;然后递归分治。 考虑用dijkstra+heap跑最短路,那么就大概是O(N^1.5logN)的(因为思想和kd-tree是差不多的吧所以时间也一样)。本地测试后两个点dijkstra+heap的时间接近spfa的一半
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<queue> 6 #include<cmath> 7 #include<algorithm> 8 #define maxn 20105 9 using namespace std; 10 inline int read() { 11 int x=0,f=1;char ch=getchar(); 12 for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; 13 for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; 14 return x*f; 15 } 16 17 struct Node { 18 int x,y,d; 19 bool operator <(const Node &tmp) const {return d>tmp.d;} 20 }; 21 struct query {int x1,y1,x2,y2,id;}a[100005],L[100005],R[100006]; 22 int ans[100005]; 23 int v[maxn][4]; 24 int n,m,Q; 25 int dis[maxn],vis[maxn]; 26 int tx[4]={1,-1,0,0},ty[4]={0,0,1,-1}; 27 priority_queue<Node> q; 28 inline int get(int x,int y) {return (x-1)*m+y;} 29 inline void dij(int x,int y,int x1,int x2,int y1,int y2) { 30 for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) dis[get(i,j)]=1000000000,vis[get(i,j)]=0; 31 q.push((Node){x,y,0}); 32 dis[get(x,y)]=0; 33 while(!q.empty()) { 34 Node now=q.top();q.pop(); 35 if(vis[get(now.x,now.y)]) continue; 36 vis[get(now.x,now.y)]=1; 37 for(int i=0;i<4;i++) { 38 int tox=now.x+tx[i],toy=now.y+ty[i]; 39 if(tox>x2||tox<x1||toy>y2||toy<y1) continue; 40 if(dis[get(tox,toy)]>dis[get(now.x,now.y)]+v[get(now.x,now.y)][i]) { 41 dis[get(tox,toy)]=dis[get(now.x,now.y)]+v[get(now.x,now.y)][i]; 42 q.push((Node){tox,toy,dis[get(tox,toy)]}); 43 44 } 45 } 46 } 47 } 48 inline void solve(int x1,int x2,int y1,int y2,int ql,int qr) { 49 if(qr<ql) return; 50 if(x1==x2&&y1==y2) { 51 for(int i=ql;i<=qr;i++) ans[a[i].id]=0; 52 return ; 53 } 54 if(x2-x1>y2-y1) { 55 int mid=(x2+x1)>>1; 56 for(int i=y1;i<=y2;i++) { 57 dij(mid,i,x1,x2,y1,y2); 58 for(int j=ql;j<=qr;j++) ans[a[j].id]=min(ans[a[j].id],dis[get(a[j].x1,a[j].y1)]+dis[get(a[j].x2,a[j].y2)]); 59 } 60 int l=0,r=0; 61 for(int i=ql;i<=qr;i++) { 62 if(a[i].x1<=mid&&a[i].x2<=mid) L[++l]=a[i]; 63 if(a[i].x1>mid&&a[i].x2>mid) R[++r]=a[i]; 64 } 65 for(int i=1;i<=l;i++) a[ql+i-1]=L[i]; 66 for(int i=1;i<=r;i++) a[ql+l+i-1]=R[i]; 67 solve(x1,mid,y1,y2,ql,ql+l-1);solve(mid+1,x2,y1,y2,ql+l,ql+l+r-1); 68 } 69 else { 70 int mid=(y2+y1)>>1; 71 for(int i=x1;i<=x2;i++) { 72 dij(i,mid,x1,x2,y1,y2); 73 for(int j=ql;j<=qr;j++) ans[a[j].id]=min(ans[a[j].id],dis[get(a[j].x1,a[j].y1)]+dis[get(a[j].x2,a[j].y2)]); 74 75 } 76 int l=0,r=0; 77 for(int i=ql;i<=qr;i++) { 78 if(a[i].y1<=mid&&a[i].y2<=mid) L[++l]=a[i]; 79 if(a[i].y1>mid&&a[i].y2>mid) R[++r]=a[i]; 80 } 81 for(int i=1;i<=l;i++) a[ql+i-1]=L[i]; 82 for(int i=1;i<=r;i++) a[ql+l+i-1]=R[i]; 83 solve(x1,x2,y1,mid,ql,ql+l-1);solve(x1,x2,mid+1,y2,ql+l,ql+l+r-1); 84 } 85 } 86 int main() { 87 memset(v,27,sizeof(v)); 88 n=read(),m=read(); 89 for(int i=1;i<=n;i++) for(int j=1;j<m;j++) v[get(i,j)][2]=v[get(i,j+1)][3]=read(); 90 for(int i=1;i<n;i++) for(int j=1;j<=m;j++) v[get(i,j)][0]=v[get(i+1,j)][1]=read(); 91 Q=read(); 92 for(int i=1;i<=Q;i++) { 93 a[i].x1=read(),a[i].y1=read(),a[i].x2=read(),a[i].y2=read(); 94 a[i].id=i;ans[i]=2147483647; 95 } 96 solve(1,n,1,m,1,Q); 97 for(int i=1;i<=Q;i++) printf("%d ",ans[i]); 98 }