2023 合肥站 热身赛 B Problem F. Flower’s Land 换根dp 依赖背包
求出包含某个点连通块大小为K的权值和最大值。
钦定1为根节点,只求根节点的答案,其实是一个依赖性01背包问题可以\(nk\)的时间内解决。
考虑进行换根操作,由于背包是取max的背包没办法进行背包的删除,然而取前后缀背包背包的合并为\(k^2\)复杂度过高。
当时还有一个想法是点分树,但是维护的信息还是太多也需要背包的合并。
我们考虑 up and down dp。
设\(f_{x,w}\)表示节点为x的子树内背包大小为\(w\)的最大价值。
设\(g_{x,w}\)表示节点为x向上不包含子树背包大小为\(w\)的最大价值。
\(f\)的转移是trivial的。
考虑\(g\)数组的求出。采用前后缀的背包进行合并。
这道题很特殊由于是树上依赖背包,我们要确保复杂度正确,直接合并\(g\)数组要枚举子树外大小,要合并的子树大小,无脑合并复杂度显然不对最坏就给卡到\(nk^2\)了。
我们基于当前子树设状态\(g_{x,w}\)表示节点为x外边大小为\(k-w\)的最大价值。
这样可以减少无用状态的枚举,保证均摊复杂度为\(nk\)。
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cctype>
#include <queue>
#include <deque>
#include <stack>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <algorithm>
#include <utility>
#include <bitset>
#include <set>
#include <map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define putl_(x) printf("%lld ",x);
#define get(x) x=read()
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;i+=1)
#define fep(n,p,i) for(int i=n;i>=p;--i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define x(w) t[w].x
#define r(w) t[w].r
#define id(w) t[w].id
#define R(w) s[w].r
#define yy p<<1|1
#define zz p<<1
#define sum(w) t[w].sum
#define mod 998244353
#define sc(A) scanf("%d",&A)
#define scs(A) scanf("%s",A);
#define put(A) printf("%d\n",A)
#define min(x,y) (x>=y?y:x)
#define max(x,y) (x>=y?x:y)
#define sub(x,y) (x-y<0?x-y+mod:x-y)
#define mes(a,k) memset(a,k,sizeof(a))
using namespace std;
const int MAXN = 40010, N = 3010;
int n, k;
int a[MAXN], sz[MAXN];
int tmp[MAXN], cnt[MAXN], ans[MAXN];
int f[MAXN][N], g[MAXN][N];
vector<int>G[MAXN];
void dfs(int x, int fa) {
f[x][1] = a[x];
sz[x] = 1;
for (int cc = 0, tn; cc < G[x].size(); ++cc) {
tn = G[x][cc];
if (tn == fa)
continue;
dfs(tn, x);
rep(0, min(sz[x], k), i)g[tn][i] = f[x][i];
mes(tmp, 0xcf);
rep(0, min(sz[x], k), i)rep(0, min(k - i, sz[tn]), j)
tmp[i + j] = max(tmp[i + j], f[x][i] + f[tn][j]);
sz[x] += sz[tn];
rep(0,min(sz[x],k),i)f[x][i]=tmp[i];
}
f[x][0] = 0;
}
void dp(int x, int fa) {
g[x][k]=0;
rep(1, k, i)ans[x] = max(ans[x], f[x][i] + g[x][i]);
//mes(tmp, 0xcf);
rep(0, k, i)tmp[i] = g[x][i];
reverse(G[x].begin(), G[x].end());
int sum = sz[x];
for (int cc = 0, tn; cc < G[x].size(); ++cc) {
tn = G[x][cc];
if (tn == fa)
continue;
mes(cnt, 0xcf);
sum -= sz[tn];
rep(0, min(sz[tn], k), i)
rep(0, min(sum, k-i), j)
{
cnt[i] = max(cnt[i], g[tn][j] + tmp[i+j]);
}
rep(0, min(k, sz[tn]), i)g[tn][i] = cnt[i];
mes(cnt, 0xcf);
rep(0, min(k, sum), i)
rep(0, min(sz[tn], k-i), j) {
cnt[i] = max(cnt[i], f[tn][j] + tmp[i+j]);
}
rep(0, k, i)tmp[i] = cnt[i];
}
for (int cc = 0, tn; cc < G[x].size(); ++cc) {
tn = G[x][cc];
if (tn != fa)
dp(tn, x);
}
}
signed main() {
// freopen("1.in", "r", stdin);
sc(n);
sc(k);
rep(1, n, i)sc(a[i]);
rep(2, n, i) {
int x, y;
sc(x);
sc(y);
G[x].pb(y);
G[y].pb(x);
}
mes(f, 0xcf);
dfs(1, 0);
dp(1, 0);
rep(1, n, i)printf("%d ", ans[i]);
return 0;
}