0%

LCA

LCA是经典的树上问题,求解两个点的最近公共祖先,我们通常会用倍增去处理。

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <bits/stdc++.h>

using namespace std;

const int MAXN=1e5+2;

vector<int> v[MAXN];
vector<int> w[MAXN];

int fa[MAXN][31],cost[MAXN][31],dep[MAXN],n,m;

void dfs(int root,int fno){
fa[root][0]=fno;
dep[root]=dep[fa[root][0]]+1;
for(int i=1;i<31;i++){
fa[root][i]=fa[fa[root][i-1]][i-1];
cost[root][i]=cost[root][i-1]+cost[fa[root][i-1]][i-1];
}
for(int i=0;i<v[root].size();i++){
if(v[root][i]==fno)continue;
cost[v[root][i]][0]=w[root][i];
dfs(v[root][i],root);
}
}

int lca(int x,int y){
int ans=0;
if(dep[x]>dep[y])swap(x,y);
int tmp=dep[y]-dep[x];
for(int i=0;tmp;i++,tmp>>=1){
// 这里是按位处理深度差,也可以直接注释代码来
if(tmp&1)ans+=cost[y][i],y=fa[y][i];
}
// for(int i=30;i>=0;--i){
// if(dep(fa[y][i])>=dep[x])ans+=cost[y][i],y=fa[y][i];
// }
if(x==y)return ans;
for(int i=30;i>=0&&y!=x;i--){
if(fa[x][i]!=fa[y][i]){
ans+=cost[x][i]+cost[y][i];
x=fa[x][i];
y=fa[y][i];
}
}
ans+=cost[x][0]+cost[y][0];
return ans;
}

int main(){
memset(fa, 0, sizeof(fa));
memset(cost, 0, sizeof(cost));
memset(dep, 0, sizeof(dep));
cin>>n>>m;
for(int i=0;i<n-1;i++){
int a,b,c;
cin>>a>>b>>c;
v[a].push_back(b);
v[b].push_back(a);
w[a].push_back(c);
w[b].push_back(c);
}
dfs(1,0);
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
cout<<lca(a,b)<<endl;
}
return 0;
}

LCA的处理常常运用于例如严格次小生成树的问题中。