传送门:点击打开链接
题意:给你一棵树,每条边有权值,求两点之间的最短距离
思路:裸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; }