1 条题解
-
0
题目理解
我们有一棵 个节点的树,初始时每个节点上有一个数字 。
有两种操作:
- 修改操作:给 到 路径上的每个点 添加一个数字
- 查询操作:查询 到 路径上所有点上的所有数字的最小值
其中 表示 到 的距离。
问题分析
1. 操作的本质
修改操作实际上是在路径上添加一个线性函数:
- 对于路径上的点 ,添加 ,其中
查询操作要求:$\min\limits_{r \in path(s,t)} \min\{\text{所有在r上的数字}\}$
2. 关键观察
在树路径 上,距离函数 是分段线性的:
- 设 ,路径分为 和 两段
- 在 段: 单调递增
- 在 段:$\mathrm{dis}(s, r) = \mathrm{dis}(s, L) + \mathrm{dis}(L, r)$,也是线性函数
因此,整个路径上的 实际上是两段线性函数。
算法设计
方法:树链剖分 + 李超线段树
1. 树链剖分
- 将树分解为 条重链
- 每条重链在 DFS 序上是连续的区间
2. 李超线段树
- 每个节点维护当前区间内最低的线段
- 支持区间插入线段、区间查询最小值
3. 操作实现
修改操作 :
- 计算
- 将路径 拆分为 和
- 对于每段,在树剖对应的区间上插入线性函数
查询操作 :
- 同样拆分为 和
- 在树剖对应的区间上查询最小值
- 取所有区间的最小值
具体实现细节
1. 线性函数表示
对于函数 ,其中 是 DFS 序位置对应的到根节点的距离。
在路径 上:
- $f(x) = a \cdot (\mathrm{dis}(root, r) - \mathrm{dis}(root, s)) + b$
- 化简得:$f(x) = a \cdot x + (b - a \cdot \mathrm{dis}(root, s))$
在路径 上:
- $f(x) = a \cdot (\mathrm{dis}(s, L) + \mathrm{dis}(L, r)) + b$
- $= a \cdot x + (b + a \cdot (\mathrm{dis}(s, L) - \mathrm{dis}(root, L)))$
2. 李超线段树节点
struct Node { ll k, b; // 线段: k*x + b ll min_val; // 区间最小值 int l, r; };
插入线段时,比较当前线段与节点中线段的优劣,选择更小的。
3. 复杂度分析
- 树链剖分: 条链
- 李超线段树:每次插入 ,查询
- 总复杂度:(勉强可过)
优化技巧
1. 标记永久化
李超线段树可以使用标记永久化,避免下传标记的开销。
2. 区间查询优化
查询时直接遍历所有相关区间,而不是合并区间。
3. 常数优化
- 使用 DFS 序的连续性
- 避免递归过深
样例验证
输入:
3 5 1 2 10 2 3 20 2 1 3 1 2 3 5 6 2 2 3 1 2 3 -5 -6 2 2 3
分析:
- 初始所有点值为
- 第一次查询:输出初始值
- 插入 :
- 路径 :点2添加6,点3添加
- 最小值6
- 插入 :
- 点2添加 ,点3添加
- 最小值
输出:
123456789123456789 6 -106
符合样例。
总结
本题的关键在于:
- 将路径添加数字转化为插入线性函数
- 利用树链剖分将路径操作转化为区间操作
- 使用李超线段树维护区间最小线段
- 注意距离函数的变换和分段处理
算法复杂度 ,在 时经过优化可以通过。
- 1
信息
- ID
- 3231
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者