【9018:1893】牧场行走

问题 C: 牧场行走

时间限制: 1 Sec  内存限制: 128 MB
提交: 74  解决: 36
[提交][状态][讨论版]

题目描述

农场主奶牛有N个约翰,被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头约翰在第i块牧场吃草。 这n块土地被n-1条路连接。 约翰可以在路上行走,第i条路连接第Ai,Bi块牧场,第i条路的长度是Li这些路被安排成任意两个约翰都可以通过这些路到达的情况,所以说这是一棵树。 这些约翰是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q对约翰之间的距离。

输入

第一行:两个被空格隔开的整数:N和Q

第二行到第n行:第i+1行有两个被空格隔开的整数:Ai,Bi,Li

第n+1行到n+Q行:每一行有两个空格隔开的整数:P1,P2,表示两头奶牛的编号。

输出

第1行到第Q行:每行输出一个数,表示那两头奶牛之间的距离。

样例输入

5 3
2 1 1
3 2 2
4 1 4
5 2 8
3 4
3 5
4 5

样例输出

7
10
13

提示

2<=n,q<=1000

题解:树上倍增lca,求树上两节点a、b的距离即为dis[a]+dis[b]-2*dis[lca(a,b)](其中dis表示该节点到根的距离)。

代码如下:

 1 #include<iostream> 
 2 #include<cstdio> 
 3 #include<queue>
 4 #define maxpow 10 
 5 using namespace std;
 6 int n,p,fa[12][1005],dep[1005],dis[1005];
 7 int cnt,head[1005];
 8 bool vis[1005];
 9 struct edge{int to,next,val;}e[2005];
10 void ins(int x,int y,int v){e[++cnt].to=y;e[cnt].next=head[x];head[x]=cnt;e[cnt].val=v;}
11 void dfs(int u){
12     vis[u]=true;
13     for(int i=1;i<maxpow;i++)
14         if(dep[u]<(1<<i)) break;
15         else fa[i][u]=fa[i-1][fa[i-1][u]];//倍增操作 
16     for(int i=head[u];i;i=e[i].next){
17         int v=e[i].to;
18         if(vis[v]) continue;
19         dep[v]=dep[u]+1; dis[v]=dis[u]+e[i].val;
20         fa[0][v]=u; dfs(v);
21     }
22 }
23 int lca(int u,int v){
24     if(dep[u]<dep[v]) swap(u,v);
25     int dif=dep[u]-dep[v];
26     for(int i=0;i<maxpow;i++) if((1<<i)&dif) u=fa[i][u];//u向上移动至于v同一深度 
27     if(u==v) return u;
28     for(int i=maxpow-1;i>=0;i--)
29         if(fa[i][u]!=fa[i][v]){u=fa[i][u]; v=fa[i][v];}//u、v同时倍增 
30     return fa[0][u];//注意这里返回fa 
31 }
32 int main()
33 {
34     scanf("%d%d",&n,&p);
35     for(int i=1;i<n;i++){
36         int x,y,l;
37         scanf("%d%d%d",&x,&y,&l);
38         ins(x,y,l); ins(y,x,l);
39     }
40     dfs(1);
41     for(int i=1;i<=p;i++){
42         int x,y; scanf("%d%d",&x,&y);
43         printf("%d
",dis[x]+dis[y]-2*dis[lca(x,y)]);
44     }
45     return 0;
46 }
原文地址:https://www.cnblogs.com/Beginner-/p/7467793.html