题意:给一棵树,求点x,y的最近公共祖先。
#include<bits/stdc++.h>
using namespace std;
#define gcd(a, b) __gcd(a,b)
const long long mod = 1e9 + 7;
const int maxn = 4e4 + 5;
#define int long long
vector<int> v[maxn];
vector<int> w[maxn];
int fa[maxn][31], cost[maxn][31], dep[maxn];
int n, m;
int a, b, c;
void dfs(int u, int k) {
fa[u][0] = k;
dep[u] = dep[k] + 1;
for (int i = 1; i <= 31; i++) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
cost[u][i] = cost[fa[u][i-1]][i-1]+cost[u][i-1];
}
int len = v[u].size();
for (int i = 0; i < len; ++i) {
if(v[u][i]!=k)
{
cost[v[u][i]][0]=w[u][i];
dfs(v[u][i],u);
}
}
}
int lca(int x, int y) {
// 令 y 比 x 深。
if (dep[x] > dep[y]) swap(x, y);
// 令 y 和 x 在一个深度。
int tmp = dep[y] - dep[x], ans = 0;
for (int j = 0; tmp; ++j, tmp >>= 1)
if (tmp & 1) ans += cost[y][j], y = fa[y][j];
// 如果这个时候 y = x,那么 x,y 就都是它们自己的祖先。
if (y == x) return ans;
// 不然的话,找到第一个不是它们祖先的两个点。
for (int j = 30; j >= 0 && y != x; --j) {
if (fa[x][j] != fa[y][j]) {
ans += cost[x][j] + cost[y][j];
x = fa[x][j];
y = fa[y][j];
}
}
// 返回结果。
ans += cost[x][0] + cost[y][0];
return ans;
}
signed main() {
int t;
cin >> t;
while (t--) {
memset(fa, 0, sizeof(fa));
memset(cost, 0, sizeof(cost));
memset(dep, 0, sizeof(dep));
// 读入树:节点数一共有 n 个。
cin>>n>>m;
for (int i = 1; i < n; ++i) {
scanf("%d %d %d", &a, &b, &c);
v[a].push_back(b);
v[b].push_back(a);
w[a].push_back(c);
w[b].push_back(c);
}
// 为了计算 lca 而使用 dfs。
dfs(1, 0);
// 查询 m 次,每一次查找两个节点的 lca 点。
for (int i = 0; i < m; ++i) {
cin>>a>>b;
printf("%d\n", lca(a, b));
}
}
return 0;
}
08-29
631
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)