ZJOI2016旅行者
Posted shxnb666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJOI2016旅行者相关的知识,希望对你有一定的参考价值。
题面
https://www.luogu.org/problem/P3350
网格图上最短路
题解
离线+分治。
最短路两种情况,穿过中间边和没穿过中间边。
对于当前区域包含的询问:
先找当前区域中间边(尽可能切成正方形)
对中间边上的点,求当前区域内所有的点对其的最短路。
如果两点被中间边切断,那这次一定能得到最优解,可以去掉。
如果两点没被中间边切断,递归下去。
// luogu-judger-enable-o2 #include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<vector> #define ri register int #define S 50050 #define INF 1e9 #define Q 100050 using namespace std; int dis[S]; bool vis[S]; int n,m,q; int x1[Q],y1[Q],x2[Q],y2[Q]; int ans[Q]; int cur[Q]; int curt[Q]; vector<int> to[S],len[S]; void add_edge(int x,int y,int z) to[x].push_back(y); len[x].push_back(z); to[y].push_back(x); len[y].push_back(z); struct node int x,d; bool operator < (const node &rhs) const return d>rhs.d; ; inline int id(int x,int y)return (x-1)*m+y; inline bool chujie(int num,int lx,int rx,int ly,int ry) if ((num-1)/m+1<lx || (num-1)/m+1>rx) return 1; if ((num-1)%m+1<ly || (num-1)%m+1>ry) return 1; return 0; void clear(int lx,int rx,int ly,int ry) for (ri i=lx;i<=rx;i++) for (ri j=ly;j<=ry;j++) dis[id(i,j)]=INF,vis[id(i,j)]=0; void dij(int lx,int rx,int ly,int ry,int s) priority_queue<node> q; dis[s]=0; q.push((node)s,0); while (!q.empty()) int x=q.top().x; q.pop(); if (vis[x]) continue; vis[x]=1; for (ri i=0;i<to[x].size();i++) if (chujie(to[x][i],lx,rx,ly,ry)) continue; if (dis[to[x][i]]>dis[x]+len[x][i]) dis[to[x][i]]=dis[x]+len[x][i]; q.push((node)to[x][i],dis[to[x][i]]); void solve(int lx,int rx,int ly,int ry,int vl,int vr) if (lx>rx || ly>ry || vl>vr) return; if (rx-lx<ry-ly) int mid=(ly+ry)/2; for (ri i=lx;i<=rx;i++) clear(lx,rx,ly,ry); dij(lx,rx,ly,ry,id(i,mid)); for (ri j=vl;j<=vr;j++) int p=cur[j]; if (dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])]<ans[p]) ans[p]=dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])]; int nl=vl-1,nr=vr+1; for (ri i=vl;i<=vr;i++) int p=cur[i]; if (y1[p]<mid && y2[p]<mid) curt[++nl]=p; if (y1[p]>mid && y2[p]>mid) curt[--nr]=p; for (ri i=vl;i<=vr;i++) cur[i]=curt[i]; solve(lx,rx,ly,mid-1,vl,nl); solve(lx,rx,mid+1,ry,nr,vr); else int mid=(lx+rx)/2; for (ri i=ly;i<=ry;i++) clear(lx,rx,ly,ry); dij(lx,rx,ly,ry,id(mid,i)); for (ri j=vl;j<=vr;j++) int p=cur[j]; if (dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])]<ans[p]) ans[p]=dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])]; int nl=vl-1,nr=vr+1; for (ri i=vl;i<=vr;i++) int p=cur[i]; if (x1[p]<mid && x2[p]<mid) curt[++nl]=p; if (x1[p]>mid && x2[p]>mid) curt[--nr]=p; for (ri i=vl;i<=vr;i++) cur[i]=curt[i]; solve(lx,mid-1,ly,ry,vl,nl); solve(mid+1,rx,ly,ry,nr,vr); int main() int c; scanf("%d %d",&n,&m); for (ri i=1;i<=n;i++) for (ri j=1;j<m;j++) scanf("%d",&c); int x=id(i,j),y=id(i,j+1); add_edge(x,y,c); for (ri i=1;i<n;i++) for (ri j=1;j<=m;j++) scanf("%d",&c); int x=id(i,j),y=id(i+1,j); add_edge(x,y,c); scanf("%d",&q); for (ri i=1;i<=q;i++) scanf("%d %d %d %d",&x1[i],&y1[i],&x2[i],&y2[i]); ans[i]=INF; cur[i]=i; solve(1,n,1,m,1,q); for (ri i=1;i<=q;i++) printf("%d\n",ans[i]); return 0;
以上是关于ZJOI2016旅行者的主要内容,如果未能解决你的问题,请参考以下文章