Codechef Black Nodes in Subgraphs(树型背包)
题目意思就是在一棵树中所有点标记为两种颜色(黑和白)
然后询问是否存在大小为X恰好有Y个黑点的连通块
这题我们可以用树型背包的方法
设$f[i][j][0]$为以$i$为根的子树中大小为$j$的连通块的黑点数目的最小值,该连通块必须经过$i$
$f[i][j][1]$为以$i$为根的子树中大小为$j$的连通块的黑点数目的最大值,该连通块必须经过$i$
那么转移的时候有
$f[x][i + j][0] = min(f[x][i + j][0], f[x][i][0] + f[u][j][0]);$
$f[x][i + j][1] = max(f[x][i + j][1], f[x][i][1] + f[u][j][1]);$
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
const int N = 5010;
int f[N][N][2], sz[N];
vector <int> v[N];
int T, n, q;
int c[N], F[N], G[N];
void dfs(int x, int fa){
sz[x] = 1;
if (c[x]) f[x][1][0] = f[x][1][1] = 1;
else f[x][1][0] = f[x][1][1] = 0;
for (auto u : v[x]){
if (u == fa) continue;
dfs(u, x);
dec(i, sz[x], 1){
rep(j, 1, sz[u]){
f[x][i + j][0] = min(f[x][i + j][0], f[x][i][0] + f[u][j][0]);
f[x][i + j][1] = max(f[x][i + j][1], f[x][i][1] + f[u][j][1]);
}
}
sz[x] += sz[u];
}
rep(i, 1, sz[x]){
F[i] = min(F[i], f[x][i][0]);
G[i] = max(G[i], f[x][i][1]);
}
}
int main(){
scanf("%d", &T);
while (T--){
scanf("%d%d", &n, &q);
rep(i, 0, n) v[i].clear();
memset(sz, 0, sizeof sz);
rep(i, 0, n) rep(j, 0, n) f[i][j][0] = 1 << 27, f[i][j][1] = 0;
rep(i, 0, n) F[i] = 1 << 27, G[i] = 0;
rep(i, 1, n - 1){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
rep(i, 1, n) scanf("%d", c + i);
dfs(1, 0);
for (; q--; ){
int x, y;
scanf("%d%d", &x, &y);
puts(F[x] <= y && G[x] >= y ? "Yes" : "No");
}
}
return 0;
}

浙公网安备 33010602011771号