题目大意:
多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离
这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离
这是自己第一道lca题目
学习了两种方法
第一种在ST算法,利用RMQ思想预处理
1 /*在线ST算法*/ 2 #pragma comment(linker, "/STACK:102400000,102400000") 3 #include <cstdio> 4 #include <iostream> 5 #include <cstring> 6 #include <algorithm> 7 using namespace std; 8 #define N 40010 9 10 int first[N] , k; 11 12 struct Edge{ 13 int x , y , w , next; 14 Edge(){} 15 Edge(int x , int y , int w , int next):x(x),y(y),w(w),next(next){} 16 }e[N<<1]; 17 18 void add_edge(int x , int y , int w) 19 { 20 e[k] = Edge(x , y , w , first[x]); 21 first[x] = k++; 22 } 23 int dp[N<<1][28]; 24 int id[N<<1] , dep[N<<1] , dis[N] , No[N] , dfs_clock; 25 void dfs(int u , int f , int d) 26 { 27 id[++dfs_clock] = u , No[u] = dfs_clock , dep[dfs_clock] = d; 28 for(int i=first[u] ; ~i ; i=e[i].next){ 29 int v = e[i].y; 30 if(v == f) continue; 31 dis[v] = dis[u]+e[i].w; 32 dfs(v , u , d+1); 33 id[++dfs_clock] = u , dep[dfs_clock] = d; 34 } 35 } 36 37 void ST(int n) 38 { 39 for(int i=1 ; i<=n ; i++) dp[i][0] = i; 40 for(int j=1 ; (1<<j)<=n ; j++){ 41 for(int i=1 ; i+(1<<j)-1<=n ; i++){ 42 int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1]; 43 dp[i][j] = dep[a]<dep[b]?a:b; 44 } 45 } 46 } 47 48 int RMQ(int l , int r) 49 { 50 int k=0; 51 while((1<<(k+1))<=r-l+1) k++; 52 int a = dp[l][k] , b = dp[r-(1<<k)+1][k]; 53 return dep[a]<dep[b]?a:b; 54 } 55 56 int LCA(int u , int v) 57 { 58 int x = No[u] , y = No[v]; 59 if(x>y) swap(x , y); 60 return id[RMQ(x , y)]; 61 } 62 63 int n , m; 64 65 int main() 66 { 67 // freopen("in.txt" , "r" , stdin); 68 int T , x , y , w; 69 scanf("%d" , &T); 70 while(T--) 71 { 72 scanf("%d%d" , &n , &m); 73 memset(first , -1 , sizeof(first)); 74 k = 0; 75 for(int i=1 ; i<n ; i++){ 76 scanf("%d%d%d" , &x , &y , &w); 77 add_edge(x , y , w); 78 add_edge(y , x , w); 79 } 80 dfs_clock = 0; 81 dis[1] = 0; 82 dfs(1 , 0 , 1); 83 ST(2*n-1); 84 while(m--){ 85 scanf("%d%d" , &x , &y); 86 int anc = LCA(x , y); 87 printf("%d\n" , dis[x]-2*dis[anc]+dis[y]); 88 } 89 } 90 return 0; 91 }