<h1>题目大意</h1>
给出一个由 $ n $个点 $ m $条边的图,现有$ q $组询问,每次需要你求出从$ x $到$ y $的一条简单路径,使路径上所有边中最小值最大,并输出这个最大值。
若不存在这样的路径,则输出$ −1 $。
<h1>解题报告</h1>
做这一道题之前,建议先看一下单次询问的最长瓶颈路这道题目。
注意解法二:我们最后的答案其实就在最小生成树上。
即我们可以证明:无向图中最小生成树中u到v的路径一定是u到v的最小瓶颈路之一。
同理:无向图中最大生成树中u到v的路径一定是u到v的最大瓶颈路之一。
所以说,对于这一道题,我们对这个无向图预先进行求最大生成树,然后这道题就成功的转化为求u到v的路径上的最小值。我们可以用LCA解决。
具体来说是我们在对f数组进行预处理时,维护一个从该节点向上跳2^k的父亲中经过的所有边的最小值。
查询?只需要在同时跳 $ u $ 和 $v$ 的时候,顺便更新最小值即可。个人感觉思想类似于树链剖分中的查询操作。
<h1>样例代码</h1>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using std::min;
using std::sort;
const int MAXN = 100000 + 5;
int N,M,Q;
float log2N;
struct Graph{
int u,v,w;
bool operator < (const Graph &other) const{
return w > other.w;
}
}e[MAXN * 2];
struct Node{
int num,depth;
bool used;
struct Edge *firstEdge;
}node[MAXN];
struct Edge{
Node s,t;
int w;
Edge *next;
}pool[MAXN 2],frog = pool;
Edge New(Node s,Node *t,int w){
Edge *ret = ++frog;
ret->s = s;ret->t = t;
ret->w = w;ret->next = s->firstEdge;
return ret;
}
inline void add(int u,int v,int w){
node[u].firstEdge = New(&node[u],&node[v],w);
node[v].firstEdge = New(&node[v],&node[u],w);
}
int fa[MAXN];
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void Kruskal(){
for(int i = 1;i <= N;i++)
fa[i] = i;
sort(e + 1,e + M + 1);
int cnt = 0;
for(int i = 1;i <= M;i++){
int fx = find(e[i].u),fy = find(e[i].v);
if(fx == fy) continue;
add(e[i].u,e[i].v,e[i].w);
fa[fy] = fx;
if(++cnt == N - 1) break;
}
}
int fMAXN,maxvMAXN;
inline void init(){
for(int i = 1;i <= N;i++){
node[i].depth = 0;
node[i].num = i;
node[i].used = false;
}
log2N = log(N)/log(2);
}
void dfs(Node *v){
for(int i = 1;i <= log2N;i++){
if(v->depth <= (1<<i)) break;
fv->num = ff[v->num][i-1];
maxvv->num = min(maxvv->num,maxvf[v->num][i-1]);
}
for(Edge *e = v->firstEdge;e;e = e->next){
if(!e->t->used){
e->t->used = true;
e->t->depth = v->depth + 1;
maxve->t->num = e->w;
fe->t->num = v->num;
dfs(e->t);
}
}
}
int query(int u,int v){
if(find(u) != find(v)) return -1;
int ret = INT_MAX;
if(node[u].depth < node[v].depth)
std::swap(u,v);
for(int j = log2N;j >= 0;j--){
if(node[u].depth - (1<<j) >= node[v].depth){
ret = min(ret,maxvu);
u = fu;
}
}
if(u == v) return ret;
for(int j = log2N;j >= 0;j--){
if(fu && fu != fv){
ret = min(ret,min(maxvu,maxvv));
u = fu;
v = fv;
}
}
return min(ret,min(maxvu,maxvv));
}
int main(){
memset(f,-1,sizeof(-1));
scanf("%d%d",&N,&M);
for(int i = 1;i <= M;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
Kruskal();
init();
dfs(&node[(1 + N) >> 1]);
scanf("%d",&Q);
while(Q--){
int x,y;
scanf("%d%d",&x,&y);
printf("%dn",query(x,y));
}
return 0;
}