HDU2586 B - How far away ?

How far away ?

problem
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.

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 }

 


posted @ 2020-01-03 09:11  小松QAQ  阅读(146)  评论(0编辑  收藏  举报