0%

Asia EC Online 2025 (I)——D. Min-Max Tree(树上dp)

思路讲解

参考代码

https://qoj.ac/submission/1298127

okay,我们来看一下,其实还是比较难的,没那么简单。

一开始我们想的是一个贪心,但是没那么贪,毕竟过的人比较少,说明大概率就是dp。

或者说容易想到,将一张图分为若干单调链一定是对的,但是怎么分那?这个就需要树上dp。

首先我们发现这个树上dp需要的是整体的值,但是我们计算的时候又需要的是单块的值,这个整体与局部的矛盾怎么解决那?那么dp计算肯定是我们优先考虑的,于是我们将局部的也并入dp。

1
2
3
// dp[i][0] 表示闭合收益 dp[i][1]表示上交最小链收益 
// dp[i][2] 表示上交最大链收益
arr3 dp[MAXN];

具体代码看我注释吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// dp[i][0] 表示闭合收益 dp[i][1]表示上交最小链收益 dp[i][2] 表示上交最大链收益
arr3 dp[MAXN];
void dfs(int u, int fa) {
ll a = A[u];
// 0 - closed with single point
// 1 - chain with minimum
// 2 - chain with maximum
// 3 - closed with two merged link
array<ll, 4> e = {0, -a, a, -INF};
for (auto &v : g[u]) {
if (v == fa) continue;
dfs(v, u);
// 上交最大链 与 最小链端
e[3] = max({A[u] < A[v] ? e[1] + dp[v][2] : -INF,
// 最大链端 与 上交最小链
A[u] > A[v] ? e[2] + dp[v][1] : -INF,
e[3] + dp[v][0]
});
// e[2] 可以怎么样拼出来那?
// 是不是我可以将 u 这个点作为单个点
// 向其上交这个最大值,相当于这个点作为一个单链
// 那么 就是 e[2] + dp[v][0]
// 你如果要和下面的块融合,那么就是dp[v][2]
// 当然我们还要考虑一下就是和别的分支的融合,那么就是e[0]+dp[v][2]。
e[2] = max(e[2] + dp[v][0],
A[u]<A[v]?e[0] + dp[v][2]:-INF
);
e[1] = max(e[1] + dp[v][0]
, (A[u]>A[v]?e[0]+dp[v][1]:-INF)
);
e[0] += dp[v][0];
}
dp[u][0]=max(e[3],e[0]);
dp[u][1]=e[1];
dp[u][2]=e[2];
}

AC代码

https://qoj.ac/submission/1303005

心路历程(WA,TLE,MLE……)