原题:http://acm.hdu.edu.cn/showproblem.php?pid=2586
LCA模板题
题意:给一个无根树,有q个询问,每个询问两个点,问两点的距离。求出 lca = LCA(X,Y) , 然后 dir[x] + dir[y] - 2 * dir[lca]
dir[u]表示点u到树根的距离
下面代码可以通过HDU的C++和G++,都不存在爆栈问题,网上很多人说会爆栈,加了申请系统栈语句,其实不用,而且好想比赛中不允许使用的
Tarjan算法跑得更快些,C++ 15ms, G++ 50ms 左右, RMQ大概60ms
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 40010;
struct Node
{
int to, w;
Node(int a = 0, int b = 0)
{
to = a;
w = b;
}
};
vector<Node> e[maxn];
int f[maxn], dis[maxn], deep[maxn], p[maxn][20], n;
void dfs(int u, int pre, int t)
{
int num;
deep[u] = t;
f[u] = pre;
num = e[u].size();
for (int i = 0; i < num; ++i)
{
int v = e[u][i].to;
if (v != pre)
{
dis[v] = dis[u] + e[u][i].w;
dfs(v, u, t + 1);
}
}
}
void init()
{
for (int j = 0; (1 << j) <= n; ++j) for (int i = 1; i <= n; ++i) p[i][j] = - 1;
for (int i = 1; i <= n; ++i) p[i][0] = f[i];
for (int j = 1; (1 << j) <= n; ++j) for (int i = 1; i <= n; ++i) if (p[i][j - 1] != -1) p[i][j] = p[p[i][j - 1]][j - 1];
}
int lca(int a, int b)
{
int i;
if (deep[a] < deep[b]) swap(a, b);
for (int i = 0; (1 << i) <= deep[a]; ++i);
i--;
for (int j = i; j >= 0; --j) if (deep[a] - (1 << j) >= deep[b]) a = p[a][j];
if (a == b)return a;
for (int j = i; j >= 0; --j)
{
if (p[a][j] != -1 && p[a][j] != p[b][j])
{
a = p[a][j];
b = p[b][j];
}
}
return f[a];
}
int main(void)
{
int T;
scanf("%d", &T);
while(T--)
{
int m, a, b, c, ans;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) e[i].clear();
for (int i = 1; i < n; ++i)
{
scanf("%d%d%d", &a, &b, &c);
e[a].push_back(Node(b, c));
e[b].push_back(Node(a, c));
}
dis[1] = 0;
dfs(1, -1, 0);
init();
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
ans = dis[a] + dis[b] - 2 * dis[lca(a, b)];
printf("%d\n", ans);
}
}
return 0;
}