题意: n个点,m条边,每条边有自己的限重,q个询问,询问满足火车从x到y的最大限重.
方法: kruscal最大生成树+树上倍增lca+rmq.
解析: 由于两个点间有可能有重边,而且我们要的是最大限重,所以选取前n-1条最大的边构成一棵树,在这棵树上进行操
作.求x到y的路径,则需要考虑x与y是否在一棵树上,不是则输出-1,在一棵树上,找出x与y的公共祖先的过程中采用
rmq记录最大的最小边权.
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std ; struct node { int from ; int to ; int val ; int next ; }; node edge[100001] ; node l[50001] ; int head[10001] ; int fa[10001][20] ; int deep[10001] ; int v[10001] ; int sum[10001][20] ; int f[10001] ; int cnt , n , m , tot , pt; int find(int x) { if(f[x] == x) return x ; else { f[x] = find(f[x]) ; return f[x] ; } } void init() { memset(head , -1 , sizeof(head)) ; memset(sum , 0x3f , sizeof(sum)) ; cnt = 1 ; for(int i = 1 ; i <= n ; i++) f[i] = i ; } void dfs(int now , int f , int dep) { v[now] = 1 ; deep[now] = dep ; for(int i = head[now] ; i != -1 ; i = edge[i].next) { int to = edge[i].to ; if(to == f) continue ; fa[to][0] = now ; sum[to][0] = edge[i].val ; dfs(to , now , dep + 1) ; } } void edgeadd(int from , int to , int val) { edge[cnt].from = from ; edge[cnt].to = to ; edge[cnt].val = val ; edge[cnt].next = head[from] ; head[from] = cnt ++ ; } int cmp(node a , node b) { return a.val > b.val ; } int lca(int x , int y) { pt = 0x3f3f3f3f ; int re ; if(deep[x] < deep[y]) swap(x , y) ; for(int i = 18 ; i >= 0 ; i--) { if(deep[fa[x][i]] >= deep[y]&&fa[x][i]!=0) pt = min(sum[x][i] , pt) ,x = fa[x][i] ; } if(x == y) return x ; for(int i = 18 ; i >= 0 ; i--) { if(fa[x][i] != fa[y][i]&&fa[x][i]&&fa[y][i]) { pt = min(sum[x][i] , pt) ; pt = min(sum[y][i] , pt) ; x = fa[x][i] , y = fa[y][i] ; } } pt = min(pt , min(sum[x][0] , sum[y][0])) ; return re ; } int main() { scanf("%d%d" , &n , &m) ; init() ; for(int i = 1 ; i <= m ; i++) { scanf("%d%d%d" , &l[i].from , &l[i].to , &l[i].val) ; } sort(l + 1 , l + m + 1 , cmp) ; for(int i = 1 ; i <= m ; i++) { int x = l[i].from , y = l[i].to ; int fx = find(x) , fy = find(y) ; if(fx != fy) { tot ++ ; f[fx] = fy ; edgeadd(x , y , l[i].val) ; edgeadd(y , x , l[i].val) ; if(tot == n-1) { break ; } } } for(int i = 1 ; i <= n ; i++) { if(!v[i]) dfs(i , 0 , 1) ; } for(int j = 0 ; (1 << j) <= n ; j++) { for(int i = 1 ; i <= n ; i++) { if(fa[fa[i][j-1]][j-1] != 0) { fa[i][j] = fa[fa[i][j-1]][j-1] ; sum[i][j] = min(sum[i][j-1] , sum[fa[i][j-1]][j-1]) ; } } } int q ; scanf("%d" , &q) ; for(int i = 1 ; i <= q ; i++) { int x , y ; scanf("%d%d" , &x , &y) ; if(find(x) != find(y)) { printf("-1\n") ; continue ; } int t = lca(x , y) ; printf("%d\n" , pt) ; } }