传送门:点击打开链接
题意:给你一棵树,每条边有权值,求两点之间的最短距离
思路:裸LCA。这里主要练习一下倍增法,感觉这种思路和代码实现很简单,而且能感觉实用性很大的,很值得学习
倍增法要理解对2的次方的枚举顺序
如果是要走固定步数,那么顺序枚举与i位与为1就行
如果是要求一个临界位置,那么要从大到小枚举
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
const int MX = 1e5 + 5;
const int M = 20;
struct Edge {
int v, nxt, cost;
} E[MX];
int Head[MX], rear;
void edge_init() {
rear = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int cost) {
E[rear].v = v;
E[rear].cost = cost;
E[rear].nxt = Head[u];
Head[u] = rear++;
}
int dep[MX], dist[MX], fa[MX][M], n;
void DFS(int u, int _dist, int _dep, int _fa) {
dist[u] = _dist; dep[u] = _dep; fa[u][0] = _fa;
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(v == u || v == _fa) continue;
DFS(v, _dist + E[i].cost, _dep + 1, u);
}
}
void presolve() {
DFS(1, 0, 0, 1);
for(int i = 1; i < M; i++) {
for(int j = 1; j <= n; j++) {
fa[j][i] = fa[fa[j][i - 1]][i - 1];
}
}
}
int LCA(int u, int v) {
while(dep[u] != dep[v]) {
if(dep[u] < dep[v]) swap(u, v);
int d = dep[u] - dep[v];
for(int i = 0; i < M; i++) {
if(d >> i & 1) u = fa[u][i];
}
}
if(u == v) return u;
for(int i = M - 1; i >= 0; i--) {
if(fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
int query(int u, int v) {
return dist[u] + dist[v] - dist[LCA(u, v)] * 2;
}
int main() {
int T, m; //FIN;
scanf("%d", &T);
while(T--) {
edge_init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= n - 1; i++) {
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
edge_add(u, v, cost);
edge_add(v, u, cost);
}
presolve();
while(m--) {
int u, v;
scanf("%d%d", &u, &v);
printf("%d\n", query(u, v));
}
}
return 0;
}