【题解】P3350 [ZJOI2016] 旅行者
\(n*m\le 2 \times 10^4\) 说明n和m最小的一个最大不会超过 \(\sqrt(2 \times 10^4)\)。
我们可以按照更长边取中间值,对于询问在两边的点必定会通过中间的这条线上的某个点,对于这点我们就可以进行分治,按照整体二分的做法把询问分到两个区间内,每次取中间所有点的最短路。
有一个优化是把最短路的初始值赋为上次最短路的值加上一个起点到这个起点的距离。
#include <bits/stdc++.h> // #define ll long long // #define int ll #define ls a[p].l #define rs a[p].r #define re register #define pb push_back #define pir pair<int,int> #define f(a,x,i) for(int i=a;i<=x;i++) #define fr(a,x,i) for(int i=a;i>=x;i--) using namespace std; const int N=1e5+10; const int M=2e4+10; const int mod=1e9+7; mt19937 rnd(251); int n,m; int read(){ int x = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } vector<pair<int,int>> v[M]; int id(int x,int y){ return (x-1)*m+y; } int ans[N]; int dis[M]; int vis[M]; void spfa(int x,int y,int xl,int yl,int xr,int yr,auto &q,int p){ queue<int> s; int d=dis[id(x,y)]; for(int i=xl;i<=xr;i++){ for(int j=yl;j<=yr;j++){ dis[id(i,j)]=p?dis[id(i,j)]+d:2e9; } } s.push(id(x,y)); vis[id(x,y)]=1; dis[id(x,y)]=0; while(!s.empty()){ int u=s.front(); s.pop(); vis[u]=0; for(auto i:v[u]){ int vv=i.first; int w=i.second; if(dis[vv]>dis[u]+w){ dis[vv]=dis[u]+w; if(!vis[vv]){ s.push(vv); vis[vv]=1; } } } } for(auto &[x,y,xx,yy,i]:q){ ans[i]=min(ans[i],dis[id(x,y)]+dis[id(xx,yy)]); } } void solve(int xl,int xr,int yl,int yr,auto &q){ if(xr-xl>=yr-yl){ int mid=(xl+xr)>>1; for(int i=yl;i<=yr;i++){ spfa(mid,i,xl,yl,xr,yr,q,i-yl); } vector<tuple<int,int,int,int,int>> q1,q2; for(auto &[x,y,xx,yy,i]:q){ if(x<mid&&xx<mid){ q1.push_back({x,y,xx,yy,i}); } if(x>mid&&xx>mid){ q2.push_back({x,y,xx,yy,i}); } } if(q1.size()>0) solve(xl,mid-1,yl,yr,q1); if(q2.size()>0) solve(mid+1,xr,yl,yr,q2); } else{ int mid=(yl+yr)>>1; for(int i=xl;i<=xr;i++){ spfa(i,mid,xl,yl,xr,yr,q,i-xl); } vector<tuple<int,int,int,int,int>> q1,q2; for(auto &[x,y,xx,yy,i]:q){ if(y<mid&&yy<mid){ q1.push_back({x,y,xx,yy,i}); } if(y>mid&&yy>mid){ q2.push_back({x,y,xx,yy,i}); } } if(q1.size()>0) solve(xl,xr,yl,mid-1,q1); if(q2.size()>0) solve(xl,xr,mid+1,yr,q2); } } signed main(){ // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); ios::sync_with_stdio(0); cin.tie(nullptr); n=read(),m=read(); for(re int i=1;i<=n;i++){ for(re int j=1;j<=m-1;j++){ int x; x=read(); v[id(i,j)].push_back({id(i,j+1),x}); v[id(i,j+1)].push_back({id(i,j),x}); } } for(re int i=1;i<=n-1;i++){ for(re int j=1;j<=m;j++){ int x; x=read(); v[id(i,j)].push_back({id(i+1,j),x}); v[id(i+1,j)].push_back({id(i,j),x}); } } int k; k=read(); vector<tuple<int,int,int,int,int>> q; for(re int i=1;i<=k;i++){ int x,y,xx,yy; x=read(),y=read(),xx=read(),yy=read(); q.push_back({x,y,xx,yy,i}); ans[i]=2e9; } solve(1,n,1,m,q); for(re int i=1;i<=k;i++){ cout<<ans[i]<<"\n"; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具