题意:
给定一个无向带权图,有一些询问,问u,v点之间的路径上最大边权值的最小为多少?也就是问u,v之间的最小瓶颈路的最大边长为?
思路:
首先的话,求出最小生成树( 瓶颈树的求法,不会自行百度 ),这样树上点u,v之间的路径唯一,且路径上的最大值即为答案,所以问题就转化为了如何快速求解u,v之间路径的最大边权。
解决上面问题的做法就是倍增法。类似于区间RMQ问题,只不过转化为树上的RMQ问题,思路类似,所以具体就看代码吧!
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <string>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int N=50010,M=10+1e5,MOD=7+1e9;
int n,m;
struct node{
int u,v,w;
} e[M];
int F[N];
vector<P> G[N];
int dep[N],anc[N][20],MX[N][20];
bool cmp(node a,node b)
{
return a.w<b.w;
}
void init()
{
for(int i = 1;i <= n;i ++) F[i]=i, G[i].clear();
memset(anc,0,sizeof(anc));
memset(MX,0,sizeof(MX));
dep[1] = 0;
}
int find_set(int u)
{
if(u == F[u]) return u;
else return F[u] = find_set(F[u]);
}
void MST()
{
sort(e,e+m,cmp);
int u,v,w,f1,f2,cnt=0;
for(int i = 0;i < m; i ++){
u = e[i].u, v = e[i].v, w = e[i].w;
f1 = find_set(u) ,f2 = find_set(v);
if(f1 != f2) {
F[f1] = f2;
cnt ++;
G[u].PB(MP(v,w)) , G[v].PB(MP(u,w));
if(cnt >= n-1) break;
}
}
}
void dfs(int u,int fa)
{
for(int i = 0;i < G[u].size(); i ++){
int v = G[u][i].FT, w =G[u][i].SD;
if(v == fa) continue;
dep[v] = dep[u] + 1;
anc[v][0] = u, MX[v][0] = w;
dfs(v,u);
}
}
void pre()
{
for(int j = 1;(1<<j) <= n; j ++){
for(int i = 1;i <= n; i ++) if(anc[i][j-1]) {
int p = anc[i][j-1];
anc[i][j] = anc[p][j-1];
MX[i][j] = max(MX[i][j-1], MX[p][j-1]);
}
}
}
int solve(int u,int v)
{
if(dep[u] < dep[v]) swap(u,v);
int x = dep[u]-dep[v] , y = 0, ans = 0;
while(x) {
if(x&1) {
ans = max(ans,MX[u][y]);
u = anc[u][y];
}
x>>=1; y++;
}
if(u == v) return ans;
for(int i = 19;i >= 0;i --) {
if(anc[u][i] && anc[u][i] != anc[v][i]) {
ans = max(ans,max(MX[u][i], MX[v][i]));
u = anc[u][i] , v = anc[v][i];
}
}
return max(ans, max(MX[u][0],MX[v][0]));
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int ca=0;
while(scanf("%d%d",&n,&m) == 2) {
if(ca) puts("");
init();
for(int i = 0;i < m; i++) {
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
MST();
dfs(1,0);
pre();
int Q ; scanf("%d",&Q);
while(Q -- ){
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n", solve(u,v));
}
ca++;
}
//system("pause");
return 0;
}