LCA最近公共祖先知识点整理

本文详细解析了HDU2586题目“Howfaraway?”的解决方案,利用Tarjan算法求解树上任意两点之间的最短路径。通过具体代码实现,展示了如何构建树结构、处理查询和计算两点间距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解报告:hdu 2586 How far away ?

Problem Description
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
解题思路:Tarjan算法求树上任意两点的最短路。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=40005;
 5 const int maxv=205;
 6 int T,n,m,x,y,z,fa[maxn],dist[maxn],ans[maxv];bool vis[maxn];
 7 vector<pair<int,int> > tree[maxn],query[maxn];
 8 void init(){
 9     for(int i=1;i<=n;++i)fa[i]=i,tree[i].clear(),query[i].clear();
10     memset(vis,false,sizeof(vis));
11     memset(dist,0,sizeof(dist));
12     memset(ans,0,sizeof(ans));
13 }
14 int query_father(int x){
15     int per=x,tmp;
16     while(fa[per]!=per)per=fa[per];
17     while(x!=per){tmp=fa[x];fa[x]=per;x=tmp;}//路径压缩
18     return x;
19 }
20 void unite(int x,int y){
21     x=query_father(x),y=query_father(y);
22     if(x!=y)fa[y]=x;
23 }
24 void Tarjan_LCA(int cur,int val){
25     vis[cur]=true;///先标记为true,这样如果同一支树上前面的祖先节点已访问,但是还没有归并到集合中去相当于为其本身,所以对下面计算两个节点的最近距离是没有影响的
26     dist[cur]=val;
27     for(size_t i=0;i<tree[cur].size();++i){
28         int v=tree[cur][i].first;
29         int w=tree[cur][i].second;
30         if(!vis[v]){
31             Tarjan_LCA(v,val+w);///先序遍历
32             unite(cur,v);///回退后续遍历归并集合
33         }
34     }
35     for(size_t i=0;i<query[cur].size();++i){///同时扫描与cur有关的点对查询
36         int to=query[cur][i].first;
37         int id=query[cur][i].second;
38         if(vis[to])ans[id]=dist[cur]+dist[to]-2*dist[query_father(to)];
39     }
40 }
41 int main(){
42     while(~scanf("%d",&T)){
43         while(T--){
44             scanf("%d%d",&n,&m);
45             init();
46             for(int i=1;i<n;++i){
47                 scanf("%d%d%d",&x,&y,&z);
48                 tree[x].push_back(make_pair(y,z));
49                 tree[y].push_back(make_pair(x,z));
50             }
51             for(int i=1;i<=m;++i){
52                 scanf("%d%d",&x,&y);
53                 query[x].push_back(make_pair(y,i));
54                 query[y].push_back(make_pair(x,i));
55             }
56             Tarjan_LCA(1,0);
57             for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
58         }
59     }
60     return 0;
61 }

 

转载于:https://www.cnblogs.com/acgoto/p/10047053.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值