树形计数背包-HDU|树形计数背包-HDU 6540 Neko and tree

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6540
题目大意:给一棵含有n个点的树,里面含有m个关键点。问你有多少种选关键点的方案使得选出的点中两两之间的距离 <= dist. (1 <= n , m , dist <= 5000) 题目思路: 重点考虑转移的时候如何表征出两点之间的距离:
【树形计数背包-HDU|树形计数背包-HDU 6540 Neko and tree】对于一颗子树,其实我们只需要知道它所选的最深关键点的深度,就可以进行dp的转移了。所以将深度放入状态中就可以直接判断子树之间是否能够转移了.所以自然我们想出以下转移方程:

之后,对于一个新增的子树,它可以向主树转移一种深度。接下来就是套树形背包的模板
1.我们设两层循环,外层循环为主树当前深度k,内层循环为子树的深度g。
2.g,k之间的组合向 max(g,k)转移.根据计数原理,新增的贡献就是方案数的乘积.
3.加上一个限制条件为:两者的距离 k + g - 2*dep[u] <= dist.(两个点的LCA就是当前的根).
4.所以转移方程为:
注意:temp为滚动数组.是上个阶段的dp[u]的值.
深度的组合是n^2的,那么整个树的复杂度为:O(n^3),所以接下来再考虑如何优化:
我们其实只需要关注那些关键点的深度。所以我们可以在dfs的过程中只保存那些关键点的深度。再一步步传给父亲节点。那么循环的时候就不是从 0 ~ n循环深度了。而是循环 树所拥有的关键点的深度(离散化的思想)。这样就等价于循环关键点的个数,而不是深度.
那么这样就保证每一对关键点只会在他们之间的LCA处计算一次答案.
复杂度为:
树形计数背包-HDU|树形计数背包-HDU 6540 Neko and tree
文章图片
关键代码 AC代码:https://paste.ubuntu.com/p/4s2NDzGPvC/

    推荐阅读