[hdu6566]The Hanged Man

博客介绍了HDU6566问题的解决方案,使用树形动态规划和重链剖分来优化算法。通过避免MAX卷积,将状态设计为考虑每个节点的父亲节点,并在重链剖分后自底向上合并状态,实现了O(n^2m)的时间复杂度。博主分享了源代码,并表示存在点分树的另一种解法。
摘要由CSDN通过智能技术生成

The Hanged Man

题解

树dp板子题。

首先 O ( n m 2 ) O\left(nm^2\right) O(nm2)的朴素dp做法应该是十分容易想到的,直接合并即可。
由于MAX卷积什么的太,太神仙了,我都没听说过,所以显然不能用来优化转移过程降低时间复杂度,我们就考虑改变一下dp状态。
首先,我们知道如果每次只合并一个数的话每次转移明显就是 O ( m ) O(m) O(m)的了,而对于这个数我们又只需要考虑它的父亲在不在,所以很快就可以想到状压,合并时看它父亲在不在。

但很明显,直接状压是不现实的, n ⩽ 50 n\leqslant 50 n50。在合并的过程中许多状态都是不必要的,或者说是可以合并在一起的,所以我们就想到了重链剖分。
对于重链剖分后的状态,我们可以从叶子节点逐渐向上加上去。
如果我们当前的合并到节点 u u u,我们就需要将节点 u u u到根节点的所有重链上最后一个点加到状态上去,记录这些点是否被选择。
我们可以先对其重儿子跑完dp,跑完重儿子后就将重儿子的dp数组合到点 u u u上,再将点 u u u加入dp。将 u u u在状态中的位置赋值为其重儿子在其状态中的位置后再依次加入加入它的儿子节点。
每次跑完儿子节点后需要完成一个去掉儿子节点状态的操作,将 d p dp dp值合并,由于儿子节点是否被选取对于其它的儿子来说是没有意义的。
而每次跑完重儿子后加入点 u u u时也需要先去掉其重儿子节点的状态,加入一个节点时只有它的父亲与重儿子可能被加入,判断这两者是否被选即可。

时间复杂度 O ( n 2 m ) O\left(n^2m\right) O(n2m),听说还有种点分树的做法,不过我确实没写出来。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 5005
typedef long long LL;
const LL INF=0x7f7f7f7f7f7f;
template<typename _T>
void read(_T 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值