Mountaineers

題目鏈接: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章