HDU 2586 - How far away?
题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=2586
题意 :
给一颗树和每条边的边权, 查询树上两点路径上的边权之和
思路 :
十分裸, 先将查询转化
查询节点x到节点y的路径上的边权和, 等于 x到它们最近公共祖先的边权和 + y到他们公共祖先的边权和
distance(x, y) = distance(x, LCA(x, y)) + distance(y, LCA(x, y))
这个也等于x到根节点的距离 + y到根节点的距离 - 2 *他们最近公共祖先到根节点距离
distance(x, y) = distance(x, root) + distance(y, root) - 2 * distance(LCA(x, y), root)
所以关键就在于维护每一个节点到根节点的距离和找出两点间的LCA节点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int MAXN = 4e4+10; typedef struct Edge{ int v, w; Edge(int v1, int w1) { v = v1, w = w1; } } Edge; vector<Edge> edge[MAXN]; int seq[2*MAXN]; int depth[2*MAXN]; int dp[2*MAXN][25]; int dis[MAXN]; int pos[MAXN]; int cnt; void Dfs(int u, int fa, int dep) { seq[++cnt] = u; pos[u] = cnt; depth[cnt] = dep; int len = edge[u].size(); for(int i = 0; i < len; i++) { int v = edge[u][i].v; if(v != fa) { dis[v] = dis[u] + edge[u][i].w; Dfs(v, u, dep+1); seq[++cnt] = u; depth[cnt] = dep; } } } void RMQ_Init(int n) { for(int i = 1; i <= n; i++) { dp[i][0] = i; } for(int j = 1; (1 << j) <= n; j++) { for(int i = 1; i + (1 << j) - 1 <= n; i++) { int a = dp[i][j-1], b = dp[i + (1 << (j-1))][j-1]; dp[i][j] = depth[a] < depth[b] ? a : b; } } } int RMQ_Query(int l, int r) { int k = 0; while((1 << (k+1)) <= r - l + 1) k++; int a = dp[l][k], b = dp[r-(1<<k)+1][k]; return depth[a] < depth[b] ? a : b; } int LCA(int u, int v) { int a = pos[u], b = pos[v]; if(a > b) { swap(a, b); } int res = RMQ_Query(a, b); return seq[res]; } void Init(int n) { for(int i = 0; i <= n; i++) { edge[i].clear(); } } int main() { int t; int n, m; int u, v, w; scanf("%d", &t); while(t--) { scanf("%d %d", &n, &m); Init(n); for(int i = 0; i < n-1; i++) { scanf("%d %d %d", &u, &v, &w); edge[u].push_back(Edge(v, w)); edge[v].push_back(Edge(u, w)); } cnt = 0; dis[1] = 0; Dfs(1, -1, 0); RMQ_Init(cnt); while(m--) { scanf("%d %d", &u, &v); printf("%d\n", dis[u] + dis[v] - 2 * dis[LCA(u, v)]); } } return 0; }