題目鏈接:Mountaineers
最大值最小的路徑肯定在MST上面,那麼我們直接求一個MST然後就是任意兩點之間的樹上路徑最小值即可。
樹上倍增即可。但是要注意同一個點的情況。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=3e5+10,M=N<<1;
int n,m,q,mx[N][18],f[N][18],par[N],cnt,g[510][510],dep[N];
int head[N],nex[M],to[M],w[M],tot;
struct node{int u,v,w;}t[M<<1];
inline int id(int x,int y){return (x-1)*m+y;}
inline void add(int a,int b,int c){to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;}
int find(int x){return x==par[x]?x:par[x]=find(par[x]);}
void dfs(int x,int fa){
dep[x]=dep[fa]+1; f[x][0]=fa;
for(int i=1;i<=16;i++)
f[x][i]=f[f[x][i-1]][i-1],mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]);
for(int i=head[x];i;i=nex[i]) if(to[i]!=fa) mx[to[i]][0]=w[i],dfs(to[i],x);
}
inline int ask(int x,int y,int res){
if(dep[x]<dep[y]) swap(x,y);
for(int i=16;i>=0;i--) if(dep[f[x][i]]>=dep[y]) res=max(res,mx[x][i]),x=f[x][i];
if(x==y) return res;
for(int i=16;i>=0;i--) if(f[x][i]!=f[y][i])
res=max(res,max(mx[x][i],mx[y][i])),x=f[x][i],y=f[y][i];
return max(res,max(mx[x][0],mx[y][0]));
}
signed main(){
cin>>n>>m>>q;
for(int i=1;i<=n*m;i++) par[i]=i;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>g[i][j];
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
if(i<n) t[++cnt]={id(i,j),id(i+1,j),max(g[i][j],g[i+1][j])};
if(j<m) t[++cnt]={id(i,j),id(i,j+1),max(g[i][j],g[i][j+1])};
}
sort(t+1,t+1+cnt,[](node a,node b){return a.w<b.w;});
for(int i=1;i<=cnt;i++){
int x=find(t[i].u),y=find(t[i].v);
if(x==y) continue;
add(t[i].u,t[i].v,t[i].w),add(t[i].v,t[i].u,t[i].w); par[x]=y;
}
dfs(1,0);
for(int i=1,x1,y1,x2,y2;i<=q;i++)
scanf("%d %d %d %d",&x1,&y1,&x2,&y2),
printf("%d\n",ask(id(x1,y1),id(x2,y2),max(g[x1][y1],g[x2][y2])));
return 0;
}