树上依赖性背包
问题 1 给定一棵 \(n\) 个节点的有根树,节点 \(u\) 有价值 \(a_u\)。选定包含根的点数 \(=k\) 的连通块,最大化总价值并输出。
设 \(f_{u,i}\) 表示 \(u\) 子树内选 \(i\) 个点的最大价值,若 \(i \ge 1\) 钦定 \(u\) 必选。
初值 \(f_{u,0}=0,f_{u,1}=a_u\)。合并 \(v\) 是 \((\max,+)\) 卷积
写成代码形如
int n, k, a[N], f[N][N], siz[N];
vector<int> e[N];
void dfs(int u) {
siz[u] = 1, f[u][1] = a[u];
for (int v : e[u]) {
dfs(v);
vector<int> f0(f[u], f[u] + siz[u] + 1);
for (int i = 1; i <= siz[u] && i <= k; i++)
for (int j = 0; j <= siz[v] && i + j <= k; j++)
chkmax(f[u][i+j], f0[i] + f[v][j]);
siz[u] += siz[v];
}
}
定理 1 限制 \(i \le \text{siz}_u \land j \le \text{siz}_v\) 时,复杂度 \(O(n^2)\)。
证明 所有 \((x,y)\) 点对只在 \(\text{lca}(x,y)\) 处贡献一次。
定理 2 额外限制 \(i+j \le k\) 时,复杂度 \(O(nk)\)。
证明 按合并顺序取 DFS 序。合并时已处理的 \(u\) 部分是连续区间,\(v\) 部分接在 \(u\) 后面。
设 \(x\) 是 \(u\) 部分倒数第 \(i\) 位,\(y\) 是 \(v\) 部分正数第 \(j\) 位,需要 \(i+j-1<k\)。点对 \((x,y)\) 只有 \(O(nk)\) 个。
问题 2 给定一棵 \(n\) 个节点的有根树,节点 \(u\) 有价值 \(a_u\) 和体积 \(\mathbf{b_u}\)。选定包含根的总体积 \(=k\) 的连通块,最大化总价值并输出。
朴素树形背包的第二维 \(i\) 不再受 \(\text{siz}_u\) 的限制,复杂度 \(O(nk^2)\) 不可接受。
将树拍到 DFS 序,设 DFS 序为 \(d_1 \sim d_n\)。令 \(f_{i,j}\) 表示从 \(d_i\) 开始,体积恰好为 \(j\) 的最大价值。
设 \(u=d_i\),决策分两种:
- 不选 \(u\),跳过 \(u\) 子树,转移 \(f_{i,j} \gets f_{i+\text{siz}_u,j}\)。
- 选定 \(u\),继续向后,转移 \(f_{i,j} \gets f_{i+1,j-b_u}+a_u\)。
边界 \(f_{n+1,0}=0\),答案 \(f_{1,k}\),复杂度 \(O(nk)\)。
DFS 序上 DP 利用 \(i \to i+\text{siz}_u\) 跳过子树,从而处理了依赖性。

浙公网安备 33010602011771号