http://acm.hdu.edu.cn/showproblem.php?pid=2586
题意:给出一颗n个节点,n-1边且有距离(带权),m次询问,问两点间最短距离。
解法:记录每一个节点到根节点(默认为1)距离,u、v两点距离为dis[u]+dis[v]-2*dis[fa].
//#include<bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SC scanf #define rep(i , j , n) for(int i = j ; i <= n ; i++) #define red(i , n , j) for(int i = n ; i >= j ; i--) #define INF 0x3f3f3f3f #define mod 1000000007 #define PI acos(-1) #define pii pair<int,int> #define fi first #define se second using namespace std; typedef long long ll ; const int maxn = 4e4+9; int head[maxn] , qhead[maxn] , tol , qtol , vis[maxn] , f[maxn] , ans[maxn] , dis[maxn]; int n , m ; struct node{ int to , next , w; }g[maxn<<1]; struct query{ int to , next , id; }q[maxn]; void init(){//初始化 ME(head , 0); ME(qhead , 0); ME(vis , 0); ME(dis , 0); tol = 0 , qtol = 0; rep(i , 1 , n){ f[i] = i ; } } void add(int u , int v , int w){//建边 g[++tol] = {v , head[u] , w}; head[u] = tol ; } void qadd(int u , int v , int id){//需查询的两点 q[++qtol] = {v , qhead[u] , id}; qhead[u] = qtol; } int find(int x){ return x == f[x] ? x :find(f[x]); } void unite(int u , int v){ f[v] = u ; } void dfs(int u , int d){ vis[u] = 1 ; for(int i = head[u] ; i ; i = g[i].next){ int v = g[i].to; dis[u] = d ; if(vis[v]) continue; dfs(v , d+g[i].w); unite(u , v); } for(int i = qhead[u] ; i ; i = q[i].next){ int v = q[i].to; if(vis[v]){ int fa = find(v); ans[q[i].id] = dis[u] + dis[v] - 2*dis[fa]; } } } void solve(){ cin >> n >> m ; init(); rep(i , 1 , n-1){ int u , v , w ; scanf("%d%d%d" , &u , &v , &w); add(u , v , w); add(v , u , w); } rep(i , 1 , m){ int u , v ; scanf("%d%d" , &u , &v); qadd(u , v , i); qadd(v , u , i); } dfs(1 , 0); rep(i , 1 , m){ cout << ans[i] << endl; } } int main() { int t;cin >> t ; while(t--){ solve(); } return 0; }