题意:给出一个$N$个节点、$M$条边的图,$Q$次询问,每一次询问两个点之间的所有可行路径中经过的边的边权的最小值中的最大值。$N \leq 10000 , M \leq 50000 , Q \leq 30000$
很套路的题目,没什么好说的,最大生成树上倍增求一段以内的最短边,然后每一次询问跳$LCA$即可。
注意:图可能是不连通的,所以在跳$LCA$之前要判断一下是否在一个连通块内。
#include<bits/stdc++.h> using namespace std; inline int read(){ ; char c = getchar(); while(!isdigit(c)) c = getchar(); ) + (a << ) + (c ^ ') , c = getchar(); return a; } vector < ] , w[]; ][] , head , depth[] , father[] , dad[] , wei[]; struct Edge{ int start , end , w; }Ed[]; bool cmpforEdge(Edge a , Edge b){return a.w > b.w;} int find(int a){return father[a] == a ? a : (father[a] = find(father[a]));} inline int min(int a , int b){return a < b ? a : b;} void LCA(int t , int pa){ depth[t] = depth[dad[t] = pa] + ; ; i < tree[t].size() ; i++) if(!depth[tree[t][i]]){ wei[tree[t][i]] = w[t][i]; LCA(tree[t][i] , t); } } inline int goLCA(int a , int b){ ; while(a != b) if(depth[a] > depth[b]){ minN = min(minN , wei[a]); a = dad[a]; } else{ minN = min(minN , wei[b]); b = dad[b]; } return minN; } int main(){ int N = read() , M = read(); ; i <= N ; i++) father[i] = i; ; i < M ; i++) Ed[i].start = read() , Ed[i].end = read() , Ed[i].w = read(); sort(Ed , Ed + M , cmpforEdge); ; i < M ; i++) if(find(Ed[i].start) - find(Ed[i].end)){ father[find(Ed[i].start)] = find(Ed[i].end); tree[Ed[i].start].push_back(Ed[i].end); tree[Ed[i].end].push_back(Ed[i].start); w[Ed[i].start].push_back(Ed[i].w); w[Ed[i].end].push_back(Ed[i].w); } int num = read(); ; i < num ; i++) pro[i][] = read() , pro[i][] = read(); ; i <= N ; i++) if(!depth[i]){ head = ; LCA(i , ); ; j < num ; j++) ]) ]) == find(i) && find(pro[j][]) == find(i)) pro[j][] = goLCA(pro[j][] , pro[j][]); ]) == find(i) || find(pro[j][]) == find(i)) pro[j][] = -; } ; i < num ; i++) printf(]); ; }