最近公共祖先
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;
}

京公网安备 11010502036488号