#分治,Dijkstra#洛谷 3350 [ZJOI2016]旅行者
阿新 • • 發佈:2021-06-21
題目
給定一張\(n*m\)的網格圖,\(q\)次詢問兩點之間距離
\(n*m\leq 2*10^4,q\leq 10^5\)
分析
首先floyd會TLE,考慮兩點間距離可以由兩段拼湊起來,
那麼列舉中間點然後跑單源最短路,但是這樣與floyd時間複雜度無異,
一些中間點實際上完全不需要,考慮分治,每次選取中線上的點在子圖內跑單源最短路
據說時間複雜度是\(O(nm\sqrt{nm}\log{nm})\)
程式碼
#include <cstdio> #include <cctype> #include <algorithm> #define rr register using namespace std; const int N=20011,inf=0x3f3f3f3f; struct node{int y,w,next;}e[N<<2]; struct rec{int lx,ly,rx,ry,rk;}q[N*5],q1[N*5],q2[N*5]; struct Two{ int d,x; inline bool operator <(const Two &t)const{ return d<t.d; } }; int as[N],Cnt,et=1,Q,dis[N],ans[N*5],n,m,Lx,Ly,Rx,Ry; Two heap[N]; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline void print(int ans){ if (ans>9) print(ans/10); putchar(ans%10+48); } inline void add(int x,int y,int w){ e[++et]=(node){y,w,as[x]},as[x]=et; e[++et]=(node){x,w,as[y]},as[y]=et; } inline signed min(int a,int b){return a<b?a:b;} inline void Push(Two w){ heap[++Cnt]=w; rr int x=Cnt; while (x>1){ if (heap[x]<heap[x>>1]) swap(heap[x],heap[x>>1]),x>>=1; else return; } } inline void Pop(){ heap[1]=heap[Cnt--]; rr int x=1; while ((x<<1)<=Cnt){ rr int y=x<<1; if (y<Cnt&&heap[y+1]<heap[y]) ++y; if (heap[y]<heap[x]) swap(heap[x],heap[y]),x=y; else return; } } inline signed rk(int x,int y){return (x-1)*m+y;} inline bool Into(int Rk){ rr int x=(Rk-1)/m+1,y=Rk-(x-1)*m; return Lx<=x&&x<=Rx&&Ly<=y&&y<=Ry; } inline void Dijkstra(int S){ if (dis[S]){ for (rr int i=Lx;i<=Rx;++i) for (rr int j=Ly;j<=Ry;++j) if (rk(i,j)!=S) dis[rk(i,j)]+=dis[S]; }else for (rr int i=Lx;i<=Rx;++i) for (rr int j=Ly;j<=Ry;++j) dis[rk(i,j)]=inf; heap[++Cnt]=(Two){0,S},dis[S]=0; while (Cnt){ rr Two t=heap[1]; Pop(); if (t.d!=dis[t.x]) continue; for (rr int i=as[t.x];i;i=e[i].next) if (Into(e[i].y)&&dis[e[i].y]>dis[t.x]+e[i].w){ dis[e[i].y]=dis[t.x]+e[i].w; Push((Two){dis[e[i].y],e[i].y}); } } } inline void dfs(int lx,int rx,int ly,int ry,int l,int r){ if (l>r) return; if (lx==rx&&ly==ry){ for (rr int i=l;i<=r;++i) ans[q[i].rk]=0; return; } Lx=lx,Rx=rx,Ly=ly,Ry=ry; if (rx-lx>ry-ly){ rr int mid=(lx+rx)>>1,tot1=0,tot2=0; for (rr int i=ly;i<=ry;++i){ Dijkstra(rk(mid,i)); for (rr int j=l;j<=r;++j) ans[q[j].rk]=min(ans[q[j].rk],dis[rk(q[j].lx,q[j].ly)]+dis[rk(q[j].rx,q[j].ry)]); } for (rr int i=l;i<=r;++i){ if (lx<=q[i].lx&&q[i].lx<=mid&&lx<=q[i].rx&&q[i].rx<=mid) q1[++tot1]=q[i]; if (mid+1<=q[i].lx&&q[i].lx<=rx&&mid+1<=q[i].rx&&q[i].rx<=rx) q2[++tot2]=q[i]; } for (rr int i=1;i<=tot1;++i) q[i+l-1]=q1[i]; for (rr int i=1;i<=tot2;++i) q[r-i+1]=q2[i]; dfs(lx,mid,ly,ry,l,l+tot1-1); dfs(mid+1,rx,ly,ry,r-tot2+1,r); }else{ rr int mid=(ly+ry)>>1,tot1=0,tot2=0; for (rr int i=lx;i<=rx;++i){ Dijkstra(rk(i,mid)); for (rr int j=l;j<=r;++j) ans[q[j].rk]=min(ans[q[j].rk],dis[rk(q[j].lx,q[j].ly)]+dis[rk(q[j].rx,q[j].ry)]); } for (rr int i=l;i<=r;++i){ if (ly<=q[i].ly&&q[i].ly<=mid&&ly<=q[i].ry&&q[i].ry<=mid) q1[++tot1]=q[i]; if (mid+1<=q[i].ly&&q[i].ly<=ry&&mid+1<=q[i].ry&&q[i].ry<=ry) q2[++tot2]=q[i]; } for (rr int i=1;i<=tot1;++i) q[i+l-1]=q1[i]; for (rr int i=1;i<=tot2;++i) q[r-i+1]=q2[i]; dfs(lx,rx,ly,mid,l,l+tot1-1); dfs(lx,rx,mid+1,ry,r-tot2+1,r); } } signed main(){ n=iut(),m=iut(); for (rr int i=1;i<=n;++i) for (rr int j=1;j<m;++j) add(rk(i,j),rk(i,j+1),iut()); for (rr int i=1;i<n;++i) for (rr int j=1;j<=m;++j) add(rk(i,j),rk(i+1,j),iut()); Q=iut(); for (rr int i=1;i<=Q;++i) ans[i]=inf,q[i]=(rec){iut(),iut(),iut(),iut(),i}; dfs(1,n,1,m,1,Q); for (rr int i=1;i<=Q;++i) print(ans[i]),putchar(10); return 0; }