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

4456: [Zjoi2016]旅行者

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 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

Sample Output

6
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\n",ans[i]);
98 }
View Code

 

posted @ 2018-10-08 16:06  wls001  阅读(162)  评论(0编辑  收藏  举报