LCA入门:
LCA(x, y):x和y的最近公共祖先
入门题目:hdu_2586
解题思路:
首先我们通过一个bfs得到所有点的深度以及所有点到1(树根)的距离;通过在bfs的过程中我们通过一个dp去的更行每一个节点的 f 数组;
然后我们通过lca直接得到查询中2个点的lca;
最后用 dist[x] + dist[y] - 2 * dist[ lca(x, y) ],得到最终的答案。
f数组的含义:f[i][j]:表示 i 这个节点的 第 2 ^ j 祖先;所以可以得到他的一个状态转移方程:
f[ i, j ] = f[ f[ i, j - 1 ], j - 1 ] 。
lca算法思路:
首先对于x和y,我们需要他们的深度;不妨设d[x] < d[y];那么我们我们首选需要做的是找到y节点的祖先设其祖先为fy, 那么我们需要找到的是d[fy] == f[x],的这个节点。我们是一定可以找到的;寻找的方法:通过f数组去寻找;然后直接让 y = fy;
然后,我们接下来首先判断此时的 x == y?,如果等于那x就是x 和 y 的最近公共祖先。否则的话我们进行后续的操作;
那么现在,我们就需要找到 x 和 y的lca,同样我们通过f数组去寻找,我们通过一个循环从最开始的f[x][i]开始找,此时f[x][i] 是一定等于 f[y][i]的(此时i = t);不断第让i自减,当f[x, i] != f[y, i]的时候就让 x = f[x, i], y = f[y, i],然后继续这个循环,最终我们一定会得到一个x,此时f[x, 0]就是x和y的lca.
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N = 4e4 + 5, M = 1e5 + 5;
int T, n, m, t;
int h[N], e[M], w[M], ne[M], idx;
int f[N][20], d[N], dist[N];
queue<int> q;
inline void init(void) {
idx = 0;
memset(h, -1, sizeof h);
memset(d, 0, sizeof d);
}
inline void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
e[idx] = a, w[idx] = c, ne[idx] = h[b], h[b] = idx ++;
}
inline void bfs(void) {
d[1] = 1; q.push(1);
while(q.size()) {
int u = q.front(); q.pop();
for(int i = h[u]; i + 1; i = ne[i]) {
int v = e[i];
if(d[v]) continue;
d[v] = d[u] + 1;
dist[v] = dist[u] + w[i];
f[v][0] = u;
for(int j = 1; j <= t; j ++)
f[v][j] = f[f[v][j - 1]][j - 1];
q.push(v);
}
}
}
inline int lca(int x, int y) {
if(d[x] > d[y]) swap(x, y);
for(int i = t; i >= 0; i --)
if(d[f[y][i]] >= d[x]) y = f[y][i];
if(x == y) return x;
for(int i = t; i >= 0; i --)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int main(void) {
// freopen("in.txt", "r", stdin);
scanf("%d", &T);
while(T --) {
scanf("%d%d", &n, &m);
init();
t = (int)(log(n) / log(2)) + 1;
for(int i = 1; i <= n - 1; i ++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
bfs();
for(int i = 1; i <= m; i ++) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", dist[x] + dist[y] - 2 * dist[lca(x, y)]);
}
}
return 0;
}