bzoj 5072
对于某一大小的连通子图包含的黑点的数目的最大值和最小值都能取到
考虑树形dp
$f[i][j]$ 表示从 $i$ 的子树中选出大小为 $j$ 的联通子图黑点数目的最小值
$g[i][j]$ 表示从 $i$ 的子树中选出大小为 $j$ 的联通子图黑点数目的最大值
树形dp转移
#include <bits/stdc++.h> const int N = 5010; #define gc getchar() inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } int head[N], cnt; struct Node { int u, v, nxt; } G[N << 1]; int n, q; int v[N]; int f[N][N], g[N][N]; int size[N]; inline void Add(int u, int v) {G[++ cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt;} void Dfs(int x, int fa) { size[x] = 1, f[x][1] = g[x][1] = v[x]; for(int i = head[x]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v != fa) { Dfs(v, x); for(int j = size[x]; j >= 1; j --) { for(int k = size[v]; k >= 1; k --) { f[x][j + k] = std:: min(f[x][j + k], f[x][j] + f[v][k]); g[x][j + k] = std:: max(g[x][j + k], g[x][j] + g[v][k]); } } size[x] += size[v]; } } for(int i = 1; i <= n; i ++) { f[0][i] = std:: min(f[0][i], f[x][i]); g[0][i] = std:: max(g[0][i], g[x][i]); } } int main() { int t = read(); for(; t; t --) { cnt = 0; memset(f, 0x3f, sizeof f); memset(g, 0xc0, sizeof g); n = read(); q = read(); for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i < n; i ++) { int u = read(), v = read(); Add(u, v), Add(v, u); } for(int i = 1; i <= n; i ++) v[i] = read(); Dfs(1, 0); for(; q; q --) { int x = read(), y = read(); if(f[0][x] <= y && y <= g[0][x]) puts("YES"); else puts("NO"); } puts(""); } return 0; }