所谓启发式合并,就是一种符合直觉的合并方法:将小的子树合并在大的子树上。
这些问题一般是相似的问题背景:都是树上的计数问题,都不能直接从上往下进行暴力,都需要从下往上计数时对子树信息进行运算从而得到父亲节点的信息。这个运算一般是启发式合并。
一般使用map保存子树的一些信息,例如树的颜色,树孩子的多少等等。选择map的原因我认为有以下几点:
- map可以非常方便地保存离散的信息,而且可以对这些离散的信息进行遍历。这样的性质可以让我们方便地将孩子节点进行合并
- map可以方便地获得大小,从而决定如何启发式合并
- map可以直接当作桶,而不必要开那么大的数组
当读入信息(树的边,节点性质等)以后,我们用递归(Dfs
函数)从根节点访问这个树
我们对根节点进行初始化,把根节点当作一个树
然后递归访问节点的每个孩子
如果一个节点有多个孩子,就要进行合并(这个时候已经处理好孩子节点了),来快速得到父亲节点的信息。
合并时我们一般要把小的树合并到大的上面。一开始的根节点也是一棵树(我们已经进行了初始化),因此只需要不断将根节点和孩子节点合并,最后得到的树就保存了子树的信息。因为在合并的过程中可能会造成信息的丢失(因为子树的重孩子不一定是树的重孩子),所以我们需要一个数组保存答案。这样就不用担心数据丢失的问题。也不用害怕修改了子节点的值会造成影响,因为是递归调用的,当访问到该节点时其子节点的值都已经保存,可以随便折腾。
重点就在合并过程(Merge
函数):合并时我们一般遍历较小的map,然后根据题目的条件进行合并。
最后得到答案。虽然挺有套路,但是如何将问题转化成可以处理的形式是问题的关键。