题解:P3350 [ZJOI2016] 旅行者
显然对每个点跑一次最短路不现实,我们考虑缩小每个点最短路的规模,而我们又是在一个矩形上,因而考虑分治。
由于题目中的限制是 \(n\times m\le 2\times 10^4\),所以 \(n\) 和 \(m\) 中的较小值 \(\le\sqrt{nm}<150\),我们考虑对矩形的长边进行分治。
对于当前分治的矩形,对其包含的每个询问考虑与分界线(即 \(mid\) 这一列)的关系。
- 如果询问的点对在分界线两侧,那么其最短路一定跨过分界线,枚举分界线上每个点,然后用该点到两个询问点的最短路更新即可,不必继续分治。
- 否则该询问的两个点在分界线一侧,其答案可能经过分界线,那么和上面一样做即可;也可能不经过分界线,那么继续分治即可。
那么我们也是对每个点跑了最短路,但是每次跑的最短路只需考虑当前分治矩形内的点即可,而分治只有 \(O(\log \max \{n,m\})\) 层,其总复杂度为 \(O(nm\min \{n,m\}\log (nm)\log \max \{n,m\})\),但似乎比这个少一只 \(\log\)(?
Code:
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#define nd(x,y) (rev?((x)-1)*im+(y):((y)-1)*in+(x))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxs=2e4+5,maxn=155,maxq=1e5+5,inf=0x3f3f3f3f;
int dis[maxn][maxs];
int in,im,iq;
bool vis[maxs],rev;
typedef pair<int,int> pr;
vector<pr> G[maxs];
int an[maxq][2];
int ans[maxq];
struct node{
int id,d;
inline friend bool operator<(node a,node b){
return a.d>b.d;
}
};
priority_queue<node> pq;
inline void dijkstra(int sx,int sy,int l,int r){
int lp=nd(1,l),rp=nd(in,r);
rep(v1,lp,rp){
dis[sx][v1]=inf;
vis[v1]=false;
}
dis[sx][nd(sx,sy)]=0;
pq.push({nd(sx,sy),0});
while(!pq.empty()){
int cur=pq.top().id;
pq.pop();
if(vis[cur])continue;
vis[cur]=true;
for(pr p:G[cur]){
int v=p.first,nw=dis[sx][cur]+p.second;
if(v>=lp&&v<=rp&&nw<dis[sx][v]){
dis[sx][v]=nw;
pq.push({v,nw});
}
}
}
}
inline void solve(int l,int r,vector<int> &v){
if(v.empty())return;
int mid=(l+r)>>1,lim=nd(in,mid);
rep(v1,1,in)dijkstra(v1,mid,l,r);
vector<int> vl,vr;
for(int v1:v){
int na=an[v1][0],nb=an[v1][1];
rep(v2,1,in){
ans[v1]=min(ans[v1],dis[v2][na]+dis[v2][nb]);
}
if(nb<=lim)vl.push_back(v1);
if(na>lim)vr.push_back(v1);
}
if(l<r){
solve(l,mid,vl);
solve(mid+1,r,vr);
}
}
int main()
{
// freopen("P3350.in","r",stdin);
// freopen("P3350.out","w",stdout);
memset(ans,0x3f,sizeof(ans));
cin>>in>>im;
rev=(in>im);
rep(v1,1,in)rep(v2,1,im-1){
int iw;
scanf("%d",&iw);
G[nd(v1,v2)].emplace_back(nd(v1,v2+1),iw);
G[nd(v1,v2+1)].emplace_back(nd(v1,v2),iw);
}
rep(v1,1,in-1)rep(v2,1,im){
int iw;
scanf("%d",&iw);
G[nd(v1,v2)].emplace_back(nd(v1+1,v2),iw);
G[nd(v1+1,v2)].emplace_back(nd(v1,v2),iw);
}
scanf("%d",&iq);
rep(v1,1,iq){
int x1,y1,x2,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
an[v1][0]=nd(x1,y1);
an[v1][1]=nd(x2,y2);
if(an[v1][0]>an[v1][1])swap(an[v1][0],an[v1][1]);
}
if(in>im)swap(in,im);
rev=false;
vector<int> v;
rep(v1,1,iq)v.push_back(v1);
solve(1,im,v);
rep(v1,1,iq)printf("%d\n",ans[v1]);
return 0;
}

浙公网安备 33010602011771号