P1967 [NOIP2013 提高组] 货车运输(MST&树上倍增)

题意

给定 n n n个点 m m m条边的无向图,每条边有边权,给定 q q q个询问,每个询问包括一个起点,终点,求该路径的最大承重(即所有路径的最小值中最大的一个)

思路

M S T MST MST+树上倍增的好题。

贪心得考虑问题,显然是都用权值较大的边更优,所以构造一棵最大生成树,然后对于每个路径 s t → e d st\rightarrow ed sted,显然这条路径在树上就是 s t − → l a c ( s t , e d ) → e d st-\rightarrow lac(st,ed)\rightarrow ed stlac(st,ed)ed

P1967 [NOIP2013 提高组] 货车运输(MST&树上倍增)_i++

因此可以考虑树上倍增来找到路径上的最小值,就是在倍增父亲的时候同时会维护最小值即可。

code

// Problem: P1967 [NOIP2013 提高组] 货车运输
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1967
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-03-20 17:04:42
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e5+5,M=2e4+5,inf=999999999,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
int dep[N],fa[N][20],mx,n,m,ww[N][20];
struct bian{
	int u,v,w;
}a[N];
int s[N];
int find(int x){return x==s[x]?x:s[x]=find(s[x]);}
void Init(int n){
	for(int i=1;i<=n;i++) s[i]=i;
}
struct edge{
	int to,nt,w;
}e[N<<1];
int h[N],cnt,vis[N];
void add(int u,int v,int w){
	e[++cnt]={v,h[u],w},h[u]=cnt;
	e[++cnt]={u,h[v],w},h[v]=cnt;
}
bool cmp(bian a,bian b){
	return a.w>b.w;
}
void dfs(int u){		//求结点深度dep
	vis[u]=1;
	for(int i=h[u];i;i=e[i].nt){
		int v=e[i].to;
		if(vis[v]) continue;
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			ww[v][0]=e[i].w;
			dfs(v);
	}
} 
int lca(int u,int v){	//倍增LCA
	if(find(u)!=find(v)) return -1;
	int ans=inf;
	if(dep[u]<dep[v]) swap(u,v);
	int delta=dep[u]-dep[v];
	for(int i=0;i<=mx;i++)
		if(delta&1<<i) ans=min(ans,ww[u][i]),u=fa[u][i];
	if(u==v) return ans;
	for(int i=mx;~i;i--)
		if(fa[u][i]!=fa[v][i]){
			ans=min(ans,min(ww[u][i],ww[v][i]));
			u=fa[u][i],v=fa[v][i];
		}
	ans=min(ans,min(ww[u][0],ww[v][0]));
	return ans;
}
int dis(int a,int b){	
	return dep[a]+dep[b]-(dep[lca(a,b)]<<1);
}
int main(){
	scanf("%d%d",&n,&m);
	mx=log(n);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
	}
	mst(ww,0x3f);
	sort(a+1,a+m+1,cmp);
	Init(n);
	for(int i=1;i<=m;i++){
		int u=a[i].u,v=a[i].v,w=a[i].w;
		int fu=find(u),fv=find(v);
		if(fu!=fv){
			s[fu]=fv;
			add(u,v,w);
		}
	}
	for(int i=1;i<=n;i++)
		if(!vis[i]) fa[i][0]=i,ww[i][0]=inf,dfs(i);
	for(int i=1; i<=mx; i++)
        for(int j=1; j<=n; j++){
            fa[j][i]=fa[fa[j][i-1]][i-1]; 
            ww[j][i]=min(ww[j][i-1], ww[fa[j][i-1]][i-1]);
        }
	int q;scanf("%d",&q);while(q--){
		int x,y;scanf("%d%d",&x,&y);
		printf("%d\n",lca(x,y));
	}
	return 0;
}