Codechef Black Nodes in Subgraphs(树型背包)

题目链接 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;

}
原文地址:https://www.cnblogs.com/cxhscst2/p/7115243.html