(large{题目链接})
(\)
(Large extbf{Solution: } large{很显然的树上背包,可以发现题目中并没有给出转播站的范围,所以容易想到转移方程f_{i,j}表示在i的子树中选了j个终端,当然这个值越大越好。})
(Large extbf{Summary: } large{A掉之后看题解,发现子树大小统计直接维护dfs就好了,我咋没想到,还是太菜了。。。})
(\)
(Large extbf{Code: })
#include <bits/stdc++.h>
#define gc() getchar()
#define LL long long
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rep(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
const int N = 3e3 + 5;
int n, m, cnt, head[N], a[N], f[N][N], size[N];
struct Edge {
int to, next, val;
}e[N << 1];
inline int read() {
int x = 0, flg = 1;
char ch = gc();
while (!isdigit(ch)) {
if (ch == '-') flg = -1;
ch = gc();
}
while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
return x * flg;
}
inline void add(int x, int y, int w) {
e[++cnt].to = y;
e[cnt].val = w;
e[cnt].next = head[x];
head[x] = cnt;
}
inline void dfs(int x) {
size[x] = 1;
for (int i = head[x]; i ; i = e[i].next) {
int u = e[i].to;
dfs(u);
size[x] += size[u];
}
}
inline void dfs2(int x) {
if (x >= n - m + 1) { f[x][1] = a[x]; return; }
for (int i = head[x]; i ; i = e[i].next) {
int u = e[i].to;
dfs2(u);
for (int j = size[x]; j > 0; --j)
for (int k = 1; k <= size[u]; ++k)
if (j - k >= 0) f[x][j] = max(f[x][j], f[x][j - k] + f[u][k] - e[i].val);
}
}
int main() {
ios::sync_with_stdio(false);
memset(f, ~0x3f, sizeof (f));
n = read(), m = read();
int t = n - m, c, x, y;
for (int i = 1; i <= t; ++i) {
c = read();
while (c--) {
x = read(), y = read();
add(i, x, y);
}
}
dfs(1);
rep(i, n - m + 1, n) a[i] = read();
rep(i, 1, n) f[i][0] = 0;
dfs2(1);
_rep(i, m, 0) if (f[1][i] >= 0) { cout << i << endl; return 0; }
}