P4281 [AHOI2008] 紧急集合 / 聚会 LCA
解题思路
这道题目要求我们在树结构中找到三个节点的最佳集合点,使得三人到达该点的总距离最短。关键点在于:
-
树的性质:n个节点n-1条边的连通无向图
-
LCA应用:利用最近公共祖先来高效计算节点间距离
-
集合点选择:三个节点的最佳集合点必定是某两个节点的LCA
#include<bits/stdc++.h> using namespace std; const int N = 5e5 + 10; // f[i][j]表示节点i的2^j级祖先 int f[N][26]; // dep[i]表示节点i的深度(根节点深度为1) int dep[N]; int n,m; // 邻接表存储树结构 vector<int> g[N]; // DFS预处理LCA信息 void dfs(int x,int fa) { dep[x] = dep[fa] + 1; // 计算当前节点深度 f[x][0] = fa; // 直接父节点 // 预处理倍增表(2^i级祖先) for(int i = 1; i <= 20; i++) { int y = f[x][i - 1]; f[x][i] = f[y][i - 1]; // 2^i = 2^(i-1) + 2^(i-1) } // 递归处理子节点 for(int i = 0; i < g[x].size(); i++) { int y = g[x][i]; if(y != fa) dfs(y,x); } } // LCA查询函数 int lca(int x,int y) { // 确保x是较深的节点 if(dep[x] < dep[y]) swap(x,y); // 将x调整到与y同一深度 for(int i = 20; i >= 0; i--){ if(dep[x] - (1 << i) >= dep[y]) x = f[x][i]; } // 如果此时已经相同,直接返回 if(x == y) return x; // 同时向上跳跃查找 for(int i = 20; i >= 0; i--){ if(f[x][i] != f[y][i]){ // 祖先不同才跳跃 x = f[x][i]; y = f[y][i]; } } return f[x][0]; // 返回最终的LCA } // 计算两点间距离 int dist(int x,int y) { return dep[x] + dep[y] - 2 * dep[lca(x,y)]; } int main() { // 输入树结构 cin >> n >> m; for(int i = 1; i < n; i++) { int x,y; cin >> x >> y; g[x].push_back(y); g[y].push_back(x); } // 预处理LCA信息(以1为根节点) dfs(1,0); // 处理每个查询 while(m--) { int x,y,z; scanf("%d%d%d",&x,&y,&z); // 计算三个两两LCA int t1 = lca(x,y), t2 = lca(x,z), t3 = lca(y,z); // 确定最佳集合点(三个LCA中不同的那个) int pos; if(t1 == t2) pos = t3; else if(t1 == t3) pos = t2; else pos = t1; // 计算总距离 int ans = dist(x,pos) + dist(y,pos) + dist(z,pos); printf("%d %d\n",pos,ans); } return 0; }
1. 三个LCA的层次关系证明
设三个节点为x、y、z,定义:
-
t1 = lca(x,y)
-
t2 = lca(x,z)
-
t3 = lca(y,z)
关键性质:这三个LCA中,必定有两个相同,且第三个要么:
-
与它们相同(当三个LCA都相同时)
-
是它们的后代(即深度更大)
为什么?
因为树的层次结构决定了:
-
如果考虑x、y、z的所有可能位置关系,它们的共同祖先链会形成一个"分叉结构"
-
假设t1和t2相同(=A),那么:
-
A是x和y的祖先
-
A也是x和z的祖先
-
那么y和z的LCA t3只能是:
-
A本身(如果y和z在A的同一子树)
-
或者A的某个后代(如果y和z在A的不同子树)
-
-
2. 为什么不同的那个更深?
考虑t1=t2=A,而t3≠A的情况:
-
t3必须是A的后代,因为:
-
t3是y和z的LCA
-
y和z都在A的子树下(因为A是它们的祖先)
-
如果y和z在A的同一直接子树,那么t3=A
-
只有当y和z在A的不同子树时,t3才会是A的某个后代(更深)
-
3. 实例验证
考虑这个树结构:
R / | \ A B C / \ | x y z
t1 = lca(x,y) = A
t2 = lca(x,z) = R
t3 = lca(y,z) = R
这里t2=t3=R,t1=A不同,且A比R更深
4. 数学归纳
用归纳法可以证明:
-
对于任何三个节点,它们的LCA集合中:
-
要么三个都相同(当它们在一条链上)
-
要么两个相同,第三个是它们的后代(更深)
-
5. 为什么选择最深的?
因为:
-
更深的LCA意味着更靠近实际节点
-
选择更深的点可以减少多个节点需要向上走的距离
-
虽然一个节点可能需要向下走,但总体上节省了更多路径
6. 反证法
假设"不同的那个"不是最深的:
-
那么存在另一个LCA比它更深
-
但是根据性质,其他两个LCA相同且比它浅
-
这与树的层次结构矛盾(不能有两个不同的LCA都比第三个深)
结论
这个性质之所以成立,完全是由树的层次结构和LCA的定义决定的。选择"不同的那个LCA"实际上就是在选择三个节点的"最深层汇聚点",这正是最小化总距离的关键所在。

浙公网安备 33010602011771号