bzoj4456 [Zjoi2016]旅行者
2017-07-24 21:25
459 查看
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 22
3
6 4
2
1 1 2 2
1 2 2 1
Sample Output
67
HINT
题解:JudgeOnline/upload/201603/4456 sol.txt正解:分治+$dijkstra$。
这道题的思路很神奇啊。。
直接暴力搞肯定炸,我们考虑分治。
这相当于平面上的分治,我们每次在横轴和纵轴中选择较长的那一条二分,二分出一条中轴,然后分别以中轴上每个点为起点,在当前这个矩形内跑最短路,并更新每个询问。递归分治时我们就把完全在左边的路径放到左边,完全在右边的路径放在右边。如果一条路径跨越了中轴线,那么它肯定已经求出最短路,就不用再递归了。
为了降低复杂度,我们使用手写堆,因为手写堆可以让每个结点只加入一次,$dijkstra$的复杂度就可以降低。
//It is made by wfj_2048~ #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <vector> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define inf ((1<<30)-1) #define N (500010) #define il inline #define RG register #define ll long long #define pos(i,j) ((i-1)*m+j) using namespace std; int head ,dis ,ans ,bl [2],n,m,num,qq; struct node{ int i,lx,ly,rx,ry; }q ,qu ; struct edge{ int nt,to,dis; }g ; struct heap{ #define fa (x>>1) #define ls (x<<1) #define rs (x<<1|1) int a ,id ,len; il void push(RG int u){ if (!id[u]) id[u]=++len,a[len]=u; RG int x=id[u]; while (fa){ if (dis[a[x]]>=dis[a[fa]]) break; swap(a[x],a[fa]),id[a[x]]=x,id[a[fa]]=fa,x=fa; } return; } il void pop(){ id[a[1]]=0,a[1]=a[len--]; if (len) id[a[1]]=1; RG int x=1,son; while (ls<=len){ son=(rs<=len && dis[a[rs]]<dis[a[ls]]) ? rs : ls; if (dis[a[x]]<=dis[a[son]]) break; swap(a[x],a[son]),id[a[x]]=x,id[a[son]]=son,x=son; } return; } #undef fa #undef ls #undef rs }Q; il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; } il void insert(RG int from,RG int to,RG int dis){ g[++num]=(edge){head[from],to,dis},head[from]=num; return; } il void dijkstra(RG int lx,RG int rx,RG int ly,RG int ry,RG int inix,RG int iniy){ for (RG int i=lx;i<=rx;++i) for (RG int j=ly;j<=ry;++j) dis[pos(i,j)]=inf; dis[pos(inix,iniy)]=0,Q.push(pos(inix,iniy)); while (Q.len){ RG int x=Q.a[1],v,nowx,nowy; Q.pop(); for (RG int i=head[x];i;i=g[i].nt){ v=g[i].to,nowx=bl[v][0],nowy=bl[v][1]; if (nowx<lx || nowx>rx || nowy<ly || nowy>ry) continue; if (dis[v]>dis[x]+g[i].dis) dis[v]=dis[x]+g[i].dis,Q.push(v); } } return; } il void solve(RG int lx,RG int rx,RG int ly,RG int ry,RG int l,RG int r){ if (lx>rx || ly>ry || l>r) return; if (l==r){ dijkstra(lx,rx,ly,ry,q[l].lx,q[l].ly); ans[q[l].i]=min(ans[q[l].i],dis[pos(q[l].rx,q[l].ry)]); return; } RG int mid,t1=l-1,t2=r+1; if (rx-lx>=ry-ly){ mid=(lx+rx)>>1; for (RG int y=ly;y<=ry;++y){ dijkstra(lx,rx,ly,ry,mid,y); for (RG int i=l;i<=r;++i) ans[q[i].i]=min(ans[q[i].i],dis[pos(q[i].lx,q[i].ly)]+dis[pos(q[i].rx,q[i].ry)]); } for (RG int i=l;i<=r;++i) if (q[i].lx<mid && q[i].rx<mid) qu[++t1]=q[i]; else if (q[i].lx>mid && q[i].rx>mid) qu[--t2]=q[i]; for (RG int i=l;i<=t1;++i) q[i]=qu[i]; for (RG int i=r;i>=t2;--i) q[i]=qu[i]; solve(lx,mid,ly,ry,l,t1),solve(mid+1,rx,ly,ry,t2,r); } else{ mid=(ly+ry)>>1; for (RG int x=lx;x<=rx;++x){ dijkstra(lx,rx,ly,ry,x,mid); for (RG int i=l;i<=r;++i) ans[q[i].i]=min(ans[q[i].i],dis[pos(q[i].lx,q[i].ly)]+dis[pos(q[i].rx,q[i].ry)]); } for (RG int i=l;i<=r;++i) if (q[i].ly<mid && q[i].ry<mid) qu[++t1]=q[i]; else if (q[i].ly>mid && q[i].ry>mid) qu[--t2]=q[i]; for (RG int i=l;i<=t1;++i) q[i]=qu[i]; for (RG int i=r;i>=t2;--i) q[i]=qu[i]; solve(lx,rx,ly,mid,l,t1),solve(lx,rx,mid+1,ry,t2,r); } return; } int main(){ #ifndef ONLINE_JUDGE freopen("tourist.in","r",stdin); freopen("tourist.out","w",stdout); #endif n=gi(),m=gi(); for (RG int i=1;i<=n*m;++i) bl[i][0]=(i-1)/m+1,bl[i][1]=(i-1)%m+1; for (RG int i=1;i<=n;++i) for (RG int j=1,w;j<m;++j) w=gi(),insert(pos(i,j),pos(i,j+1),w),insert(pos(i,j+1),pos(i,j),w); for (RG int i=1;i<n;++i) for (RG int j=1,w;j<=m;++j) w=gi(),insert(pos(i,j),pos(i+1,j),w),insert(pos(i+1,j),pos(i,j),w); qq=gi(); for (RG int i=1;i<=qq;++i) q[i].i=i,q[i].lx=gi(),q[i].ly=gi(),q[i].rx=gi(),q[i].ry=gi(),ans[i]=inf<<1; solve(1,n,1,m,1,qq); for (RG int i=1;i<=qq;++i) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- BZOJ4456 [Zjoi2016]旅行者
- BZOJ 4456 [Zjoi2016]旅行者
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
- 【BZOJ 4456】【UOJ #184】【ZJOI 2016】旅行者
- bzoj 4456: [Zjoi2016]旅行者
- BZOJ4456 ZJOI2016旅行者(分治+最短路)
- bzoj 4456: [Zjoi2016]旅行者 分治+最短路
- [分治 最短路] BZOJ 4456 [Zjoi2016]旅行者
- Bzoj4456 [Zjoi2016]旅行者
- 4456: [Zjoi2016]旅行者
- 4456: [Zjoi2016]旅行者 分治+最短路
- ●BOZJ 4456 [Zjoi2016]旅行者
- 4456: [Zjoi2016]旅行者
- 4456: [Zjoi2016]旅行者|分治+最短路
- 【分治+最短路】UOJ#184【ZJOI2016】旅行者
- bzoj 4455: [Zjoi2016]小星星
- 【BZOJ 4455】 4455: [Zjoi2016]小星星 (容斥原理+树形DP)
- [BZOJ4573][UOJ#195][Zjoi2016][LCT][离线]大森林
- bzoj4456: [Zjoi2016]旅行者
- BZOJ 4455 & UOJ 185 [ZJOI2016]小星星