最近公共祖先
LCA(Least Common Ancestors),即最近公共祖先,指对于有根树 T 的两个结点 u 、v ,最近公共祖先 LCA(T,u,v) 表示一个结点 x, 满足 x 是 u、v 的祖先且 x 的深度尽可能大。
树上倍增
int anc[maxn][32]; // 结点 i 的第 2^j 个祖先 int depth[maxn]; // 深度 int dis[maxn]; // 距离 void dfs(int x, int fa, int d) { depth[x] = d; for(int i = head[x]; ~i; i = e[i].next) { int j = e[i].to; if (j == fa) continue; anc[j][0] = x; dis[j] = dis[x] + e[i].val; dfs(j, x, d+1); } } void init(int n) { // 预处理 dfs(1, 0, 0); int m = 31 - __builtin_clz(n); for(int j = 1; j <= m; ++ j) { for(int i = 1; i <= n; ++ i) { anc[i][j] = anc[anc[i][j-1]][j-1]; } } } int lca(int a, int b) { // 最近公共祖先 if (depth[a] < depth[b]) swap(a,b); int h = depth[a] - depth[b]; for(int i = 31-__builtin_clz(h); i >= 0; -- i) { if ((h>>i) & 1) a = anc[a][i]; } if (a != b) { for(int i = 31-__builtin_clz(depth[b]); i >= 0; -- i) { if (anc[a][i] != anc[b][i]) { a = anc[a][i]; b = anc[b][i]; } } a = anc[a][0]; } return a; }
树链刨分
(https://acm.ecnu.edu.cn/contest/354/problem/A/) #include<bits/stdc++.h> using namespace std; const int maxn = 5e4+1; struct node{ int to, w, next; }e[maxn<<1]; int head[maxn], tot; void addedge(int x, int y, int val) { e[++tot] = {y, val, head[x]}, head[x] = tot; e[++tot] = {x, val, head[y]}, head[y] = tot; } int dis[maxn], depth[maxn]; int fa[maxn], siz[maxn], son[maxn]; void dfs1(int u,int f){ fa[u]=f; depth[u] = depth[f] + 1; siz[u]=1; int maxsize=-1; for(int i=head[u];~i;i=e[i].next){ int v=e[i].to; if(v==f) continue; dis[v] = dis[u] + e[i].w; dfs1(v,u); siz[u]+=siz[v]; if(siz[v]>maxsize){ maxsize=siz[v]; son[u]=v; } } } int cnt, dfn[maxn], top[maxn]; void dfs2(int u,int t){ dfn[u]=++cnt; top[u]=t; if(!son[u]) return ; dfs2(son[u],t); for(int i=head[u];~i;i=e[i].next){ int v=e[i].to; if(v==fa[u]||v==son[u]) continue ; dfs2(v,v); } } int LCA(int x,int y){ while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]]) swap(x,y); x=fa[top[x]]; } return depth[x]<depth[y]?x:y; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; memset(head, -1, sizeof head); for(int i = 1; i < n; ++ i) { int x, y, z; cin >> x >> y >> z; addedge(x+1, y+1, z); } dfs1(1, 1); dfs2(1, 1); int T; cin >> T; while(T --) { long long a[6], res = 0; cin >> a[1] >> a[2] >> a[3] >> a[4] >> a[5]; a[1] ++, a[2] ++, a[3] ++, a[4] ++, a[5] ++; for(int i = 5; i >= 2; -- i) { int x = 1, y = 1, z = -1, t; for(int j = 1; j <= i; ++ j) { for(int k = j+1; k <= i; ++ k) { int ro = LCA(a[j], a[k]); if (z < depth[ro]) z = depth[ro], x = j, y = k, t = ro; } } res += dis[a[x]] + dis[a[y]] - 2*dis[t]; if (y == i) swap(a[x], a[i-1]); else swap(a[x], a[i]), swap(a[y], a[i-1]); a[i-1] = t; } cout << res << "\n"; } return 0; }