题意:给你一张图,保证了边数大于等于节点的个数,求一棵生成树,使得路径最大边权尽量小。
思路:首先求出最小生成树,然后把无根树转化为有根树,用RMQ类似的原理求出cost【i】【j】数组,即 i 节点往上j个祖先的边权最大值,最后用lca求出两点之间的最小瓶颈路即可,套路题!
#include <bits/stdc++.h>
#define mk make_pair
#define pi pair<int,int>
using namespace std;
const int inf = 1e9;
int n,m,u,v,w;
vector<pi>G[500004];
struct edge {
int u,v,w;
bool operator < (const edge & t)const {
return w < t.w;
}
}a[100005];
int p[400005],f[400005][20],cost[400005][20],dep[400005];
int find(int x) {
return x == p[x]?x:p[x]=find(p[x]);
}
void kruskal()
{
sort(a+1,a+1+m);
int tot = 0;
for(int i=1;i<=m;i++)
{
int u = find(a[i].u);
int v = find(a[i].v);
int w = a[i].w;
if(u != v)
{
p[u] = v;
G[a[i].u].push_back(mk(a[i].v,w));
G[a[i].v].push_back(mk(a[i].u,w));
++tot;
}
if(tot == n-1)break;
}
}
void dfs(int u,int fa,int c,int d)
{
f[u][0] = fa;
cost[u][0] = c;
dep[u] = d;
for(int i=1;i<=19;i++)
{
f[u][i] = f[f[u][i-1]][i-1];
cost[u][i] = max(cost[u][i-1],cost[f[u][i-1]][i-1]);
}
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i].first;
int w = G[u][i].second;
if(v == fa)continue;
dfs(v,u,w,d+1);
}
}
int solve(int u,int v)
{
if(dep[u] < dep[v])swap(u,v);
int ans = -inf;
for(int i=19;~i;i--)
if( dep[f[u][i]] >= dep[v])
{
ans = max(ans,cost[u][i]);
u = f[u][i];
}
if(u == v)return ans;
for(int i=19;i>=0;i--)
if(f[u][i] != f[v][i])
{
ans = max(ans,cost[u][i]);
ans = max(ans,cost[v][i]);
u = f[u][i];
v = f[v][i];
}
ans = max(ans,max(cost[u][0],cost[v][0]));
return ans;
}
int main()
{
// freopen("make.in","r",stdin);
// freopen("1.out","w",stdout);
int kase = 0;
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)p[i] = i,G[i].clear();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
}
kruskal();
dfs(1,0,0,0);
int q;
scanf("%d",&q);
if(kase++)puts("");
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
int ans = solve(l,r);
printf("%d\n",ans);
}
}
}