专栏文章

题解:P12382 [蓝桥杯 2023 省 Python B] 树上选点

P12382题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miojuovt
此快照首次捕获于
2025/12/02 20:23
3 个月前
此快照最后确认于
2025/12/02 20:23
3 个月前
查看原文

题意:

在一棵树上找若干个点 PiP_i,保证这些点两两不相邻(不存在有边直接相连),同一深度只选一个点。

目标:求出 maxVi\max \sum V_i

数据范围:1n2×105,1Vi1041 \le n \le 2 \times 10^5, 1 \le V_i \le 10^4

分析:

常规想法

根据树的背景和 Pi,PjP_i, P_j 两两不相邻的条件,不难想到方法:常规树状 DP 求最大值。
状态:dpi,0/1dp_{i, 0/1} 表示以 ii 为根的子树中,选或不选 ii 的最大点权和;

答案:maxdp1,0,dp1,1\max dp_{1, 0}, dp_{1, 1}

初始状态:dpi,1=Vidp_{i, 1} = V_i
对于 Pi,PjP_i, P_j 不能相邻,当转移时选了 curcur 这个点,则他的子节点 nxtnxt 和父节点 fafa 都不能选,由于从下到上递归,无需考虑 fafa 节点。
然而,对于同一深度内只能有一个 PiP_i,就会有一些麻烦了。因为深度相同的情况下,可能会牵扯到其他子树,贸然转移会出现矛盾,导致结果不合法(~虽然我觉得硬要做这种做法也能做出来~)。
这个时候,我们就需要转移优先取舍。

换思路想法

想看正解思路的可以跳过。
通常情况下,当一个做法可能性较小或者写不出来的时候,可以关注题目的限制,转化优先的条件
比如,常规写法是优先考虑如何处理父子节点,我们可以换成优先考虑同一层节点
有一些题目是两个考虑方向都正确的,如 Peaks,可以优先处理每个询问的 xx,也可以优先预处理边权。

最终想法

可以按深度建立权值线段树(略)
状态:dpidp_i 表示选了 ii 的最大点权和;

答案:maxdpi\max dp_i

转移:按深度上往下转移,每次取上一层最大的值进行转移,在要注意不能是父节点,所以要维护一个次大值,如果最大值是父节点,那么就继承次大值。总之就是 dpi=Vi+maxjfaidpjdp_i = V_i + \max\limits_{j \ne fa_i} dp_j

初始状态:dpi=0dp_i = 0

总结

优先考虑的问题十分重要,在一个优先考虑的可能性想不通时,试试换一种优先方式做题。

代码(部分)

CPP
// 继承上一层的最大值,次大值 
int tpmaxi = maxi, tpcmaxi = cmaxi;
for(auto nxt : point[d]) // 枚举深度为d的点
{
	if(dp[fa[cur]] < maxi) dp[cur] = maxi + v[cur];
	else dp[cur] = cmaxi + v[cur];
	// 更新这一层临时的最大值,次大值 
	if(dp[cur] > tpmaxi) tpcmaxi = tpmaxi, tpmaxi = dp[cur];
	else if(dp[cur] > tpcmaxi) tpcmaxi = dp[cur];
} 
// 刷新上一层到这一层的最大值,次大值
maxi = tpmaxi, cmaxi = tpcmaxi; 

评论

0 条评论,欢迎与作者交流。

正在加载评论...