HDU2586 B - How far away ?
How far away ?
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
Sample Output
10
25
100
100
解题思路:
先解读一下题意,先输入n和m,
就是给你n个房间,它们能构成一个无向无环图,然后再给你n-1条边以及他们的权值
然后就是m次询问,每次询问给你两个房间号,让你求他们之间的最短的路径长
我在做的时候受到了别人的启发,即:两个点之间的最短路径长就是这两个点到根的路径长的和再减去两倍的他们的LCA到根的长
其实一开始想要建立一个数组w[i][j]来代表i到j的距离,但是发现太麻烦
而用第一个方法则很容易就将所有的点到根节点的路径长给算出来
然后就是继续倍增的LCA板子,求出他们的LCA就行了
代码如下:
1 #include <bits/stdc++.h> 2 #define N 40050 3 using namespace std; 4 5 int n,m; 6 struct node 7 { 8 int v,w,next; 9 }e[2*N]; 10 int tot,head[N]; 11 int father[N<<1][30]; 12 int depth[N<<1]; 13 int weight[N<<1]; 14 15 int tol; 16 inline void add(int u,int v,int w) 17 { 18 e[tol].v=v; 19 e[tol].w=w; 20 e[tol].next=head[u]; 21 head[u]=tol++; 22 } 23 24 inline void dfs(int now,int fa) 25 { 26 depth[now]=depth[fa]+1; 27 father[now][0]=fa; 28 for(int i=1;(1<<i)<=depth[now];++i) 29 father[now][i]=father[father[now][i-1]][i-1]; 30 for(int i=head[now];i;i=e[i].next) 31 { 32 if(e[i].v!=fa) dfs(e[i].v,now); 33 } 34 } 35 36 inline int lca(int u,int v) 37 { 38 if(depth[u]<depth[v]) swap(u,v); 39 int d=depth[u]-depth[v]; 40 for(int i=0;i<=20;++i) 41 if((1<<i)&d) u=father[u][i]; 42 if(u==v) return u; 43 for(int i=20;i>=0;--i) 44 { 45 if(depth[father[u][i]]<=0) continue; 46 if(father[u][i]!=father[v][i]) 47 { 48 u=father[u][i]; 49 v=father[v][i]; 50 } 51 } 52 return father[u][0]; 53 } 54 55 //这个部分就是处理所有点到根节点的距离 56 //其实是仿照上面倍增处理father数组的方法 57 bool vis[N<<1]; 58 inline void dealw(int a,int frontw) 59 { 60 vis[a]=true; 61 for(int i=head[a];i;i=e[i].next) 62 { 63 if(!vis[e[i].v]) 64 { 65 weight[e[i].v]=e[i].w+frontw; 66 dealw(e[i].v,weight[e[i].v]); 67 } 68 } 69 } 70 71 int main() 72 { 73 int T; 74 scanf("%d",&T); 75 while(T--) 76 { 77 memset(depth,0,sizeof(depth)); 78 memset(father,0,sizeof(father)); 79 memset(head,-1,sizeof(head)); 80 memset(vis,0,sizeof(vis)); 81 memset(weight,0,sizeof(weight)); 82 int x,y,z; 83 tol=1; 84 scanf("%d%d",&n,&m); 85 for(int i=1;i<n;++i) 86 { 87 scanf("%d%d%d",&x,&y,&z); 88 add(x,y,z); 89 add(y,x,z); 90 } 91 dfs(1,0); 92 dealw(1,0); 93 weight[1]=0; 94 for(int i=0;i<m;++i) 95 { 96 cin>>x>>y; 97 z=lca(x,y); 98 //cout<<z<<endl; 99 cout<<weight[x]+weight[y]-2*weight[z]<<endl; 100 } 101 } 102 return 0; 103 }