概念
大家可能觉得没有听过“决斗”,是不是都认为是我瞎编的?(没错,就是我瞎编的。 )
但是“决斗”可以解决一些小问题,可以帮助初学者快速解决入门阶段很多的树上问题。(注意,只是入门阶段。)
我们先来想想入门阶段的树上问题有哪些?
求以 u u u 为根节点的子树大小、求从根节点开始到叶子的最长的链(点权或边权)、求一些树的统计与价值……
其中,第一类问题可以用 DFS \text{DFS} DFS 求,第三类问题一般要用启发式合并等操作来求,第二类问题,也就是和链有关的树上问题可以用决斗操作来解决。
用法
一般有这几个操作:
对于一颗树的当前节点,贪心地选择其子树(“选择”可以看成是一个决斗的过程,胜者被选择,败者不会再继续参加竞选);
从下往上地暴力更新子树信息。
树上决斗可以用在比较算法、自然选择、竞选等题目当中。
例题
[例1]
题目描述
给定一棵树,树上有点权,点权为小于等于 9 9 9 的正整数,保证树的根节点到任意叶子结点的高度统一,我们取任意一条以根节点为起点,以任意叶子节点为终点的一条路径作为一条链,认定这条链上某一个点的贡献为这个点的点权乘上 10 10 10 的其高度次幂,这条链的价值为这条链上所有点的贡献的累加,请输出任意一个叶子节点使得这条链的价值达到最大,特别地,叶子结点的高度为 1 1 1,每个非叶子节点的高度为其儿子的高度加 1 1 1,根节点的点权为 0 0 0。
分析
可能题目的表达有点问题,大家将就着看吧。
题目形式化:
记 h i h_i hi 为第 i i i 个节点的高度, s o n i son_i soni 为 i i i 的儿子, Leaf \text{Leaf} Leaf 函数判断是否为叶子节点, v i v_i vi 为 i i i 的贡献,则:
h i = { Leaf ( i ) = true → 1 Leaf ( i ) = false → h s o n i + 1 h_i=\begin{cases}\text{Leaf}(i)=\text{true}\to 1\\\text{Leaf}(i)=\text{false}\to h_{son_i}+1\end{cases} hi={Leaf(i)=true→1Leaf(i)=false→hsoni+1
v i = 1 0 h i a i v_i=10^{h_i}a_i vi=10hiai
设 A A A 为叶子节点点集, l u l_u lu 为以 u u u 为终点的链的价值, r r r 为根节点, P u P_u Pu 为从根节点到 u u u 路径的点集,则:
l u = ∑ v P u ( u ∈ A ) l_{u}=\sum{v_{P_u}}(u\in A) lu=∑vPu(u∈A)
也就是说:
l u = ∑ 1 0 h P u = ∑ 1 0 h s o n P u + 1 ( u ∈ A ) l_{u}=\sum{10^{h_{P_u}}}=\sum{10^{h_{son_{P_u}+1}}}(u\in A) lu=∑10hPu=∑10hsonPu+1(u∈A)
求任意一个满足 l l l 最大的叶子节点。
接下来开始分析。
我们注意到,点权始终小于等于 9 9 9,高度统一,于是我们就知道了:这道题是个傻题。
为什么呢?实际上,这是一个两个数相同位数比大小的题,举个例子:
1234
1234
1234 和
1235
1235
1235 和
1199
1199
1199 进行比较,可以画出这样一颗树:
其中,根据题目的描述,我们知道,它是根据上面的贡献比下面大来计算的,故直接输出最大的那个数即可。
实现简单,不放代码了。
关于这道题还有很多变形,比如终点不一定是叶子、起点不一定是根、高度不一定统一等,请读者自己思考。
也就是说,树上决斗可以用来解释多位数比大小的底层逻辑。
因为树上决斗的入门比较简单,知道原理就可以独行天下,故只有一道例题。
总结
没什么总结,你已经学会树上决斗了,快去 AK IOI 吧!