(2023GESP八级)洛谷P10113题:用树结构解决员工管理的问题

一、问题分析
这道题目描述了一个公司的员工层级关系,可以抽象为一个树形结构,其中0号员工是根节点(老板)。我们需要解决的问题是:给定一组员工,找到能够管理所有这些员工的最低层级的共同上级(即编号最大的最近公共祖先)。
二、树结构基础
在计算机科学中,树是一种重要的数据结构,由节点和边组成,具有以下特点:
有一个特殊的节点称为根节点
每个节点有零个或多个子节点
除了根节点外,每个节点有且只有一个父节点
在本问题中,公司的管理结构正好形成了一棵树,其中每个员工(除老板外)都有一个直接领导(父节点)。
三、最近公共祖先(LCA)算法
最近公共祖先(Lowest Common Ancestor)是指在一棵树中,两个节点的共同祖先中离它们最近的节点。对于多个节点,可以依次计算它们的LCA。
四、解决方案
我们可以采用以下步骤解决这个问题:
预处理每个节点的深度和祖先信息
对于每组查询,找出所有节点的LCA
如果有多个可能的LCA,选择编号最大的那个
五、C++代码实现
以下是完整的C++实现代码,包含详细注释:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
const int LOG = 20; // 足够大的对数级别
vector<int> parent(MAXN); // 存储每个节点的直接领导
vector<int> depth(MAXN); // 存储每个节点的深度
vector<vector<int>> up(MAXN, vector<int>(LOG)); // 倍增表
// 预处理函数,构建倍增表
void preprocess(int n) {
// 0号节点是根节点,深度为0,没有父节点
depth[0] = 0;
up[0][0] = 0; // 根节点的2^0祖先还是自己
// 预处理其他节点
for(int i = 1; i < n; ++i) {
depth[i] = depth[parent[i]] + 1;
up[i][0] = parent[i]; // 2^0祖先就是直接领导
}
// 填充倍增表
for(int j = 1; j < LOG; ++j) {
for(int i = 0; i < n; ++i) {
up[i][j] = up[up[i][j-1]][j-1];
}
}
}
// 查找两个节点的LCA
int lca(int u, int v) {
// 确保u是较深的节点
if(depth[u] < depth[v]) swap(u, v);
// 将u提升到与v相同的深度
for(int j = LOG-1; j >= 0; --j) {
if(depth[u] - (1 << j) >= depth[v]) {
u = up[u][j];
}
}
// 如果此时u和v相同,则已经找到LCA
if(u == v) return u;
// 否则,同时提升u和v直到它们的父节点相同
for(int j = LOG-1; j >= 0; --j) {
if(up[u][j] != up[v][j]) {
u = up[u][j];
v = up[v][j];
}
}
return parent[u];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
// 读取每个员工的直接领导
for(int i = 1; i < N; ++i) {
cin >> parent[i];
}
// 预处理倍增表
preprocess(N);
int Q;
cin >> Q;
while(Q--) {
int m;
cin >> m;
vector<int> employees(m);
for(int i = 0; i < m; ++i) {
cin >> employees[i];
}
// 找出所有员工的LCA
int current_lca = employees[0];
for(int i = 1; i < m; ++i) {
current_lca = lca(current_lca, employees[i]);
}
cout << current_lca << "\n";
}
return 0;
}六、代码解析
预处理阶段:我们使用倍增法预处理每个节点的2^j级祖先,这样可以快速跳跃查找祖先节点。
LCA查找:对于两个节点,我们首先将它们调整到同一深度,然后同时向上跳跃查找共同祖先。
查询处理:对于每组查询,我们依次计算所有节点的LCA,最终结果即为所求的主持人。
希望这篇文章能帮助你理解树结构和LCA算法,并成功解决这道题目!
原创内容 转载请注明出处
