|
|
|
@ -689,24 +689,85 @@ int main() {
|
|
|
|
|
|
|
|
|
|
看数据范围就知道暴力肯定是会$TLE$飞的,所以我们要考虑如何$dp$(代码习惯写$dfs$)
|
|
|
|
|
|
|
|
|
|
仔细思考一下我们发现点$i$走$k$步能到达的点分为以下两种
|
|
|
|
|
仔细思考一下我们发现点$i$走$k$步能到达的点分为以下两种:
|
|
|
|
|
|
|
|
|
|
- 在$i$的子树中(由$i$点往下)
|
|
|
|
|
- 经过$i$的父亲(由$i$点往上)
|
|
|
|
|
- ① 在$i$的子树中(由$i$点往下)
|
|
|
|
|
- ② 经过$i$的父亲(由$i$点往上)
|
|
|
|
|
|
|
|
|
|
这样的问题一般可以用两次$dfs$解决
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
这样的问题一般可以用两次$dfs$解决。
|
|
|
|
|
|
|
|
|
|
定义状态:
|
|
|
|
|
- $f[i][j]$表示$i$点往下$j$步范围内的点权之和
|
|
|
|
|
- $g[i][j]$表示$i$点往上和往下走$j$步范围内点权之和
|
|
|
|
|
- $g[i][j]$表示$i$点往上和往下走$j$步范围内点权之和:【答案在这里】
|
|
|
|
|
|
|
|
|
|
第一次$dfs$我们求出所有的$f[i][k]$,这个简单,对于节点$u$和其儿子$v$:
|
|
|
|
|
|
|
|
|
|
第一次$dfs$我们求出所有的$f[n][k]$,这个比较简单,对于节点$u$和其儿子$v$,$f[u][k] += f[v][j - 1]$就行了。(第一次$dfs$已知叶子节点推父亲节点)
|
|
|
|
|
**初始值**
|
|
|
|
|
$$f[i][0]=a[i]$$
|
|
|
|
|
> **解释**:每个节点,向下走$0$步,也就是一步不走,那还是它自己的点权,也就是$f[i][0]=a[i]$
|
|
|
|
|
|
|
|
|
|
第二次$dfs$我们通过已经求出的$f$数组推$g$数组,对于$u$和$u$的儿子$v$,
|
|
|
|
|
**递推式**
|
|
|
|
|
$$f[u][j] = \sum_{v \in son[u]}f[v][j - 1]$$
|
|
|
|
|
|
|
|
|
|
第二次$dfs$我们通过已经求出的$f$数组推$g$数组,对于$u$和$v$,
|
|
|
|
|
$$g[v][k] += (g[u][k - 1] - f[v][k - 2])$$
|
|
|
|
|
|
|
|
|
|
注意数组下表不要越界。$g[i][j]$的初始值应该赋为$f[i][j]$,因为根节点的$g[i][j]$就是$f[i][j]$。(第二次$dfs$已知父亲节点推儿子节点)
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
题目简单地来说就是:
|
|
|
|
|
给你一棵 $n$ 个点的树,点带权,对于每个节点求出距离它不超过 $k$ 的所有节点权值和 $m_i$。
|
|
|
|
|
|
|
|
|
|
对于树中的某个节点而言,距离它不超过$k$的节点主要来源于两方面:
|
|
|
|
|
- 一个是该节点的子节点中距离该节点不超过距离$k$的节点的权值和
|
|
|
|
|
- 一个是该节点向上沿着父节点方向不超过距离$k$的点的权值和
|
|
|
|
|
|
|
|
|
|
对于子节点方向的节点的权值和,我们可以先通过普通的树形$DP$计算出来。
|
|
|
|
|
|
|
|
|
|
因此,我们先写一个$DP$计算出子树中距离该点不超过$k$的点的权值和。
|
|
|
|
|
|
|
|
|
|
**1、状态表示**
|
|
|
|
|
$f[u][k]$表示以$u$为根节点的树中,距离$u$不超过$k$的子节点的权值和。
|
|
|
|
|
|
|
|
|
|
**2、状态转移**
|
|
|
|
|
$$f[u][j]=val[u]+\sum_{v \in son[u]}f[v][j−1] \ j \in [1,k]$$
|
|
|
|
|
|
|
|
|
|
到节点$u$不超过距离$k$,即距离$son$不超过$k−1$,然后加在一起即可。同时$u$节点本身也是答案,因为$u$节点本身是不超过距离$0$的节点。
|
|
|
|
|
|
|
|
|
|
**3、换根$DP$**
|
|
|
|
|
这个题目本身是个无根树,如果我们认为规定编号为$1$的节点是根的话,那么对于祖宗节点$1$来说,$f[1][k]$就是距离$1$节点不超过距离$k$的节点的权值和。因为祖宗节点是没有父亲节点的,所以我们就不需要考虑沿着父节点方向的节点权值和。
|
|
|
|
|
|
|
|
|
|
令:$g[u][k]$表示所有到$u$节点的不超过距离$k$的节点的权值和。根据刚刚的分析:$g[1][k]=f[1][k]$
|
|
|
|
|
|
|
|
|
|
这个就是我们换根$DP$的 **初始化**。其实受这个的启发,我们完全可以去把每个点都当作根,然后暴力跑出答案,但是这个暴力做法的时间复杂度是$O(n^2)$的,会超时。
|
|
|
|
|
|
|
|
|
|
所以当我们将祖宗节点从节点$1$换为另一个节点的时候,我们只能通过数学上的关系来计算出$g$数组元素的值。这个也是换根$DP$的意义。
|
|
|
|
|
|
|
|
|
|
我们看下面的图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
红色框是非常好理解的,直接写成$f[u][k]$即可。上面的部分,我们可以写成$g[fa(u)][k-1]$。
|
|
|
|
|
因为到$u$不超过$k$的距离,即距离它的父亲节点不超过$k−1$的距离。
|
|
|
|
|
|
|
|
|
|
但是这么写对吗?
|
|
|
|
|
|
|
|
|
|
答案是不对的,$g[fa(u)][k-1]$和$f[u][k]$是有重复部分的。我们需要减去这段重复的部分,那么关键问题是重复部分如何表示?
|
|
|
|
|
|
|
|
|
|
重复部分肯定是出现在了红色框中,红色框中到$fa(u)$不超过距离$k−1$,即距离$u$不超过$k-2$,同时重复部分又恰好是节点$u$的子节点,所以这部分可以表示为:$f[u][k-2]$。
|
|
|
|
|
|
|
|
|
|
所以最终的结果就是:
|
|
|
|
|
|
|
|
|
|
$$\large g[u][k]=f[u][k]+g[fa(u)][k−1]−f[u][k−2]$$
|
|
|
|
|
|
|
|
|
|
但是上述方程成立的条件是$k\geq 2$的。
|
|
|
|
|
|
|
|
|
|
所以我们还得想一想$\leq 1$的时候。
|
|
|
|
|
|
|
|
|
|
如果$k=0$,$g[u][0]$其实就是$val[u]$,因为不超过距离$0$的点只有本身。
|
|
|
|
|
|
|
|
|
|
如果$k=1$,那么$g[u][1]$其实就是$f[u][1]+val[fa(u)]$,因为沿着父节点方向距离$u$不超过$1$的点,只有父节点,而树中,父节点是唯一的。沿着子节点方向,其实就是$u$的各个子节点,而这些子节点可以统统用$f[u][1]f[u][1]$表示。
|
|
|
|
|
|
|
|
|
|
#### [$P6419$ $Kamp$](https://www.luogu.com.cn/problem/P6419)
|
|
|
|
|
https://www.cnblogs.com/Troverld/p/14601347.html
|
|
|
|
|