马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街。商店街有n个商店,并且它们之间的道路构成了一颗树的形状。
第i个商店只卖第i种物品,小苗对于这种物品的喜爱度是wi,物品的价格为ci,物品的库存是di。但是商店街有一项奇怪的规定:如果在商店u,v买了东西,并且有一个商店w在u到v的路径上,那么必须要在商店w买东西。小葱身上有m元钱,他想要尽量让小苗开心,所以他希望最大化小苗对买
到物品的喜爱度之和。这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为OI选手的你,你能帮帮他吗?
对于一般的树上背包,时间复杂度是 O(nm) O ( n m ) 的。对于多重背包,我们用二进制优化一下,时间复杂度为 O(nmlog) O ( n m log ) 。用单调队列优化,时间复杂度 O(nm) O ( n m ) 。枚举每个点为必选点,时间复杂度 O(n2m) O ( n 2 m ) 。
考虑点分治,每次从分治重心跑树上依赖背包,这样就将时间复杂度优化成了 O(mnlogn) O ( m n log n ) 。
/************************************************
* Au: Hany01
* Date: Aug 29th, 2018
* Prob: BZOJ4182 Shopping
* Email: [email protected] & [email protected]
* Inst: Yali High School
************************************************/
#include
using namespace std;
typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define SZ(a) ((int)(a).size())
#define ALL(a) a.begin(), a.end()
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
static int _, __; static char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 503, maxm = 4003;
int n, m, beg[maxn], v[maxn << 1], e, nex[maxn << 1], dp[maxn][maxm], q[maxm], head, tail, W[maxn], V[maxn], C[maxn], vis[maxn], Ans, rt, mxch[maxn], sz[maxn], ns;
inline void add(int uu, int vv) { v[++ e] = vv, nex[e] = beg[uu], beg[uu] = e; }
void getrt(int u, int pa) {
mxch[u] = 0, sz[u] = 1;
for (register int i = beg[u]; i; i = nex[i]) if (v[i] != pa && !vis[v[i]])
getrt(v[i], u), sz[u] += sz[v[i]], chkmax(mxch[u], sz[v[i]]);
chkmax(mxch[u], ns - sz[u]);
if (mxch[u] < mxch[rt]) rt = u;
}
void DP(int u, int pa, int wsum) {
for (register int j = beg[u]; j; j = nex[j]) if (v[j] != pa && !vis[v[j]]) {
//if (W[v[j]]) {
rep(p, W[v[j]]) {
q[head = tail = 0] = wsum;
for (int i = p + wsum; i <= m; i += W[v[j]]) {
while (head <= tail && q[head] + C[v[j]] * W[v[j]] < i) ++ head;
if (head <= tail) dp[v[j]][i] = dp[u][q[head]] + (i - q[head]) / W[v[j]] * V[v[j]];
else dp[v[j]][i] = -INF;
for (q[++ tail] = i; head < tail && dp[u][q[tail]] + (i - q[tail]) / W[v[j]] * V[v[j]] > dp[u][q[tail - 1]] + (i - q[tail - 1]) / W[v[j]] * V[v[j]]; -- tail) q[tail - 1] = q[tail];
}
}
//} else For(i, 0, m) dp[v[j]][i] = dp[u][i] + C[v[j]] * V[v[j]];
DP(v[j], u, wsum + W[v[j]]);
For(i, wsum + W[v[j]], m) chkmax(dp[u][i], dp[v[j]][i]);
}
}
void solve(int u) {
//if (W[u]) {
For(i, 0, W[u] - 1) dp[u][i] = -INF;
For(i, W[u], m) dp[u][i] = min(i / W[u], C[u]) * V[u];
//} else For(i, 0, m) dp[u][i] = C[u] * V[u];
DP(u, 0, W[u]), chkmax(Ans, dp[u][m]);
vis[u] = 1;
for (register int i = beg[u]; i; i = nex[i]) if (!vis[v[i]])
ns = sz[v[i]], rt = 0, getrt(v[i], 0), solve(v[i]);
}
int main()
{
#ifdef hany01
freopen("bzoj4182.in", "r", stdin);
freopen("bzoj4182.out", "w", stdout);
#endif
static int uu, vv, T;
for (T = read(), mxch[0] = INF; T --; ) {
n = read(), m = read(), Ans = e = 0;
For(i, 1, n) V[i] = read(), beg[i] = vis[i] = 0;
For(i, 1, n) W[i] = read();
For(i, 1, n) C[i] = read();
For(i, 2, n) uu = read(), vv = read(), add(uu, vv), add(vv, uu);
rt = 0, ns = n, getrt(1, 0), solve(rt), printf("%d\n", Ans);
}
#ifdef hany01
cerr << clock() * 1. / CLOCKS_PER_SEC << endl;
#endif
return 0;
}