dWoi Round 2 B 题解
Description
给定一棵树,每一条边有边权
t_i ,每一个点有点权w_i ,t_i 对应的值决定这条边连接的两个点的值的大小关系(等于,不等于,没有关系),求满足所有t_i 的关系且w_i \in [1,R] 的点权赋值情况一共有多少种,并且求出最小的点权和。
注:本文有视频讲解,请在文章最下方查看 qwq。
Solution
两问分别考虑,都要考虑树形 dp。
第一问
设
设
答案即为
第二问
设
设
答案即为
优化
(思路来自 Euler_Pursuer)
如果按照上面的方法打代码,你会发现最终复杂度为
我们尝试把
操作比较简单,对于第一问,预处理前缀和,对于第二问预处理
总结
本题为一道简单的树形 dp,只要想清楚升维就没了。
下面是代码的主要部分,仅供参考(写的很难看):
void dfs1 (int cur, int fa) {
for (int i = 1; i <= r; i++) dp1[cur][i] = 1ll;
bool isleaf = false;
for (int p = head[cur]; p; p = e[p].v) {
if (e[p].u == fa) continue;
isleaf = true;
dfs1(e[p].u, cur);
int t = e[p].w;
if (t == 0) {
for (int i = 1; i <= r; i++) {
long long sum = s[e[p].u][r];
sum += Mod;
sum -= dp1[e[p].u][i];
sum %= Mod;
dp1[cur][i] *= sum;
dp1[cur][i] %= Mod;
}
}
if (t == 1) {
for (int i = 1; i <= r; i++) {
dp1[cur][i] *= s[e[p].u][r];
dp1[cur][i] %= Mod;
}
}
if (t == 2) {
for (int i = 1; i <= r; i++) {
dp1[cur][i] *= dp1[e[p].u][i];
dp1[cur][i] %= Mod;
}
}
}
if (!isleaf)
for (int i = 1; i <= r; i++)
dp1[cur][i] = 1;
for (int i = 1; i <= r; i++) {
s[cur][i] = s[cur][i - 1] + dp1[cur][i];
s[cur][i] %= Mod;
}
}
void dfs2 (int cur, int fa) {
for (int i = 1; i <= r; i++) dp2[cur][i] = 1ll * i;
for (int p = head[cur]; p; p = e[p].v) {
if (e[p].u == fa) continue;
dfs2(e[p].u, cur);
int t = e[p].w;
if (t == 0) {
for (int i = 1; i <= r; i++) {
dp2[cur][i] += min(pre[e[p].u][i - 1], suf[e[p].u][i + 1]);
}
}
if (t == 1) {
for (int i = 1; i <= r; i++) {
dp2[cur][i] += pre[e[p].u][r];
}
}
if (t == 2) {
for (int i = 1; i <= r; i++)
dp2[cur][i] += dp2[e[p].u][i];
}
}
pre[cur][0] = 0x3f3f3f3f;
suf[cur][r + 1] = 0x3f3f3f3f;
for (int i = 1; i <= r; i++) pre[cur][i] = min(pre[cur][i - 1], dp2[cur][i]);
for (int i = r; i >= 1; i--) suf[cur][i] = min(suf[cur][i + 1], dp2[cur][i]);
}
视频讲解
您是否觉得文字太过枯燥?本人提供了不知道是否生动有趣的视频讲解
设置在 2021 年 8 月 23 日 17 点 30 分发布,因此可能提前看不到。