洛谷 P1967 货车运输 LCA + 最小生成树
两点之间边权最大值的最小值一定在图的最小生成树中取到。
求出最小生成树,进行倍增即可。
Code:
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 10000 + 3; const int maxm = 100000 + 3; const int inf = 10000000+3; const int logn = 30; int st[maxm], ed[maxm], cost[maxm]; int head[maxm],to[maxm<<1], nex[maxm<<1], val[maxm<<1], cnt; int F[maxn][logn], minv[maxn][logn], dep[maxn]; int n,m; int cmp(int i,int j) { return cost[i] > cost[j]; } struct Make_Tree { int A[maxm],p[maxn]; int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } inline void add_edge(int u,int v,int c) { nex[++cnt] = head[u], head[u] = cnt, to[cnt] = v, val[cnt] = c; } inline void solve() { for(int i = 1;i <= m;++i)A[i] = i; for(int i = 1;i <= n;++i)p[i] = i; sort(A+1,A+1+m,cmp); for(int i = 1;i <= m;++i) { int cur = A[i]; int a = st[cur], b = ed[cur]; int x = find(a); int y = find(b); if(x == y)continue; add_edge(a,b,cost[cur]); add_edge(b,a,cost[cur]); p[x] = y; } } }T; void dfs(int u,int fa,int c,int deep) { F[u][0] = fa, minv[u][0] = c, dep[u] = deep; for(int v = head[u]; v ;v = nex[v]) if(to[v] != fa){ dfs(to[v],u,val[v],deep+1); } } inline int solve(int a,int b) { if(dep[a] > dep[b])swap(a,b); int ans = inf; if(dep[b] != dep[a]) { for(int i =logn-1;i>=0;--i) if(dep[a] <= dep[F[b][i]]) { ans = min(ans,minv[b][i]); b = F[b][i]; } } if(a == b)return ans; for(int i = logn-1;i>=0;--i) if(F[a][i] != F[b][i]) { ans = min(ans,min(minv[a][i],minv[b][i])); a = F[a][i], b = F[b][i]; } ans = min(ans,min(minv[a][0],minv[b][0])); return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) scanf("%d%d%d",&st[i],&ed[i],&cost[i]); T.solve(); for(int i = 1;i <= n;++i) if(!dep[i])dfs(i,0,0,1); for(int i = 1;i < logn-1;++i) for(int j = 1;j <= n;++j) { minv[j][i] = min(minv[j][i-1], minv[F[j][i-1]][i-1]); F[j][i] = F[F[j][i-1]][i-1]; } int asks; scanf("%d",&asks); for(int i = 1;i <= asks;++i) { int a,b; scanf("%d%d",&a,&b); if(T.find(a) != T.find(b) || a>n|| b>n)printf("-1\n"); else printf("%d\n",solve(a,b)); } return 0; }