1 条题解
-
0
题目概述
公司组织结构是一棵树,根节点是总经理(编号1)。每个员工有一个能力值 ,各不相同。每天总经理被解雇后,由能力最高的直接下属接任。
员工可以“取消”一位同事(将其能力降为0),来加速自己成为总经理的进程。需要回答多个查询:对于员工 ,在恰好取消一位同事的情况下,最少需要多少天才能成为总经理。
问题分析
关键观察
- 晋升规则:每天总经理被能力最高的直接下属取代
- 树结构:公司是树形结构,父节点是直接上级
- 取消操作:可以让一个员工能力变为0,影响晋升路径
- 目标:最小化成为总经理所需天数
问题难点
- 需要动态计算取消不同员工的影响
- 树规模很大()
- 需要高效处理多个查询
算法思路
核心思想:重链剖分 + 线段树
步骤1:建立能力树
将原树按照能力值重新构建:
- 节点编号变为能力值()
- 边表示晋升关系:从高能力指向低能力
步骤2:计算晋升顺序
使用大根堆模拟晋升过程:
- 初始将根节点(能力最高的总经理)入堆
- 每次取出堆顶(当前能力最高的候选人)
- 将其所有下属加入堆中
- 这样得到员工成为总经理的自然顺序
步骤3:重链剖分优化
在能力树上进行重链剖分,用线段树维护:
- 每个节点的“深度偏移量”
- 快速查询路径上的最大值
步骤4:计算取消影响
对于每个员工 ,计算如果取消某个员工, 能提前多少天成为总经理:
- 在能力树上, 的祖先路径上的节点会阻碍 晋升
- 取消一个员工相当于移除一个障碍
- 使用重链剖分快速计算最优取消方案
算法详解
数据结构
线段树 (segtree)
支持区间加和查询全局最大值:
class segtree { vector<pii> B; // 区间边界 vector<ll> S, T; // 最大值、懒标记 // 支持区间加和全局最大值查询 };重链剖分 (hld)
在能力树上进行剖分:
class hld { vector<int> f, e, h, t, l; // 父节点、子树大小、重儿子、链顶、DFS序 segtree T; // 线段树 // 更新节点u到根的路径 void update(int u, int d) { while (~u) { T.update(1, l[t[u]], l[u], d); // 更新整条链 u = f[t[u]]; // 跳到上一条链 } } };主算法流程
1. 构建能力树
vector<vector<int>> g(n); // 能力树 for (auto [u, v] : e) // 原树边 g[s[u]].emplace_back(s[v]); // 按能力值重建2. 计算自然晋升顺序
priority_queue<int> q; q.emplace(s[0]); // 根节点(能力最高的总经理) while (!q.empty()) { int u = q.top(); q.pop(); o.emplace_back(u); // 记录晋升顺序 for (int i : g[u]) // 所有下属 q.emplace(i); }3. 计算取消影响
for (int i = 0; i < n; i++) { int u = o[i]; // 当前考虑的员工 h.update(u, -I); // 标记该员工被"阻碍" r[u] = i - max(0, h.query()); // 计算提前天数 h.update(u, I + 1); // 恢复 }关键公式
对于员工 在自然顺序中的位置 :
- 如果没有取消:需要 天
- 最优取消后:需要 天
- 提前天数:
样例解析
样例输入
5 4 1 2 2 1 # p2=1, p3=2, p4=2, p5=1 3 5 1 2 4 # 能力值 5 3 1 4 # 查询的员工能力树构建
原树:
1(s=3) / \ 2 5(s=4) / \ 3 4(s=2) (s=5) (s=1)能力树(按能力值):
根: 5 (最高能力) 下属: 3, 4, 1, 2计算过程
-
自然晋升顺序:5, 3, 4, 1, 2
-
对于员工5(能力4):
- 自然位置:第3个(从0开始?实际代码中可能调整)
- 取消员工2后,只需1天
- 输出:1
-
对于员工3(能力5):
- 自然位置:第0个(已经是总经理)
- 输出:0
其他员工类似计算。
复杂度分析
- 构建能力树:
- 计算晋升顺序:(堆操作)
- 重链剖分:
- 处理每个员工:(重链剖分更新)
- 总复杂度:
对于 可以接受。
算法亮点
- 能力树转换:将组织结构转化为按能力排序的树
- 重链剖分:高效处理树上路径查询和更新
- 线段树维护:动态计算阻碍影响
- 堆模拟:确定自然晋升顺序
- 独立查询处理:预处理所有可能情况, 回答查询
总结
这道题的核心在于:
- 问题转化:将晋升问题转化为树上的路径问题
- 数据结构:重链剖分 + 线段树处理动态路径查询
- 预处理:计算所有员工在最优取消下的结果
- 高效查询: 回答每个查询
这种"重链剖分 + 预处理"的方法在解决树上路径相关问题时非常有效,特别是在需要处理多个查询的场景下。
- 1
信息
- ID
- 4869
- 时间
- 1500ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者