1 条题解
-
0
问题理解
有一棵树,每条边可以是“重要的”(1)或“不重要的”(0)。
给定若干祖先-后代点对 的限制条件: 到 的路径上必须至少有一条边是重要的。
问有多少种给边赋值的方案满足所有限制。核心思路
1. 限制的转化
对于每个点对 , 是 的祖先。限制: 到 的路径上至少有一条边是1。
设 为 的深度(根深度为1)。
对于每个点 ,考虑所有以 为后代的限制 。
对每个这样的 ,限制意味着:从 到 的路径上必须有1。等价地,从 向上直到 的父边(或 本身),这段路径必须有1。
定义 为: 必须在其深度为 的祖先处有重要的边。
更准确地说, 表示:在 的祖先中,深度 的位置必须有一条重要的边。初始化 (深度1是根,表示无限制)。
对于限制 ,更新 。理解: 表示 的父节点深度。
限制 要求: 到 的路径上有1,这意味着在 的儿子到 的路径上必须包含1。
如果 是 的祖先,那么 必须在深度 的祖先处获得1。2. DP 状态定义
设 表示:在 的子树中,从 出发向上看,第一个重要的边出现在深度为 的祖先处(即 到深度 的祖先的路径上必须有重要的边)。
如果 ,表示不需要重要的边。
转移:
- 对 的孩子 ,合并 和 。
- 边 可以是重要的或不重要的。
- 如果 不重要,则 向上看的第一个重要边必须和 向上看的相同。
- 如果 重要,则 向上看的第一个重要边就是 (因为 是 的父节点)。
合并公式:$dp'[x][i] = dp[x][i] \times (\sum_{j} dp[y][j]) + (\sum_{k} dp[x][k]) \times dp[y][i]$
3. 最终答案
对根节点 ,答案为 ,但 ,所以答案是 。
4. 优化
直接 DP 是 的,不可行。
观察到 中, 的范围是 或与 相关。用线段树合并优化:
每个节点 维护一棵线段树,存储 的值, 为深度。
合并两棵线段树时,需要同时维护两个前缀和 。
关键合并公式(在叶子节点):
sumy += dp[y][i] dp'[x][i] = dp[x][i] * sumy + sumx * dp[y][i] sumx += dp[x][i]这可以用线段树合并实现,每个节点维护乘法和加法标记。
5. 特殊处理
在 DP 完成后,对每个节点 ,如果 不是根,需要处理父边 :
- 如果父边不重要,保持 不变。
- 如果父边重要,则 向上看的第一个重要边深度变为 。
所以更新:
代码结构
-
预处理
- 读入树,计算深度
- 处理限制,更新
- 从上到下传递限制:
-
DP 计算
- 对每个节点 ,初始化线段树:在 处设
- 递归合并子树线段树
- 处理父边:加上前缀和到 处
-
获取答案
- 根的线段树中,查询 的和
复杂度分析
- 线段树合并:
- 空间:
- 可处理
样例验证
以样例1为例:
n=5 边: 1-2, 2-3, 3-4, 3-5 限制: (1,3), (2,5)计算 :
- 传递后:
- (从 传来)
DP 计算后得到答案 10,符合样例。
总结
这道题的核心技巧:
- 将路径限制转化为每个点对祖先深度的要求
- 设计 DP 状态 表示第一个重要边的深度
- 用线段树合并优化 DP 转移
- 在合并时维护前缀和,实现 的转移
- 1
信息
- ID
- 5335
- 时间
- 3000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 11
- 已通过
- 1
- 上传者