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号
浙公网安备 33010602011771号