1 条题解
-
0
题目描述
给定一棵以 为根,包含 个节点的有根树,每个节点有一个初始权值。需要处理 次操作,操作分为三种类型:
- 类型 1:将节点 的点权增加
- 类型 2:将以节点 为根的子树中所有节点的点权都增加
- 类型 3:查询从节点 到根节点 的路径上所有节点的点权之和
输入格式
- 第一行:两个整数 ,表示节点数和操作数
- 第二行: 个整数,表示各节点的初始权值
- 接下来 行:每行两个整数 ,表示树中的一条边
- 接下来 行:每行表示一个操作
- 操作 1:
1 x a - 操作 2:
2 x a - 操作 3:
3 x
- 操作 1:
输出格式
对于每个类型 3 的操作,输出一行答案。
数据范围
- 所有输入数据的绝对值不超过
算法分析
问题难点
- 子树操作:需要高效处理以任意节点为根的子树修改
- 路径查询:需要快速计算从任意节点到根的路径和
- 大规模数据:,需要 或 的算法
核心思路:树链剖分
树链剖分可以将树结构转化为线性序列,从而利用线段树等数据结构高效处理。
基本概念
- 重儿子:节点 的所有儿子中子树大小最大的儿子
- 重链:由重儿子连接形成的链
- 轻边:非重边
- DFS 序:通过特定的 DFS 遍历顺序为节点编号
剖分过程
-
第一次 DFS:
- 计算子树大小
- 确定重儿子
- 计算节点深度 和父节点
-
第二次 DFS:
- 优先遍历重儿子,保证重链在 DFS 序中连续
- 记录每个节点的 DFS 序
- 记录每个节点所在重链的顶端
数据结构设计
线段树维护
建立线段树维护 DFS 序列,支持:
- 区间加:用于子树修改
- 区间求和:用于路径查询
操作处理
-
单点修改(类型 1):
- 直接在线段树的 位置加上
-
子树修改(类型 2):
- 子树在 DFS 序中对应区间
- 对该区间执行区间加操作
-
路径查询(类型 3):
- 从节点 开始,不断向上跳转到链顶
- 对于每条链 ,查询对应区间和并累加
- 直到到达根节点
算法流程
-
预处理阶段:
进行两次 DFS,完成树链剖分 根据 DFS 序建立线段树 -
操作处理阶段:
for 每个操作: if 类型1: 线段树单点加(dfn[x], a) if 类型2: 线段树区间加(dfn[x], dfn[x]+size[x]-1, a) if 类型3: res = 0 while x != 0: res += 线段树区间和(dfn[top[x]], dfn[x]) x = fa[top[x]] 输出 res
复杂度分析
- 预处理:两次 DFS,
- 单点/子树操作:线段树操作,
- 路径查询: 次链跳转,每次 ,总共
- 总复杂度:,可以满足题目要求
实现细节
-
DFS 序性质:
- 重链在 DFS 序中连续
- 子树在 DFS 序中连续
-
线段树实现:
- 需要支持懒标记的区间加和区间求和
- 注意数据范围,使用
long long存储结果
-
边界处理:
- 根节点的处理
- 空子树的处理
总结
本题是树链剖分的经典应用,通过将树结构线性化,可以高效处理子树修改和路径查询。关键在于理解树链剖分的原理和 DFS 序的性质,以及如何利用线段树维护序列信息。
- 1
信息
- ID
- 5297
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者