题目大意
有一颗树,每个节点相当于是一种物品,有三个因素价值、价格、个数。
在树上选一个联通块,然后做多重背包,要求每种物品必须选。
求最大价值。
点分治
我们进行点分治。
对于分治中心,要么在联通块中,要么不在。
不在的情况就是递归继续处理。
在的话,以分治中心为根造一颗树,然后做依赖多重背包。
具体做法是,在dfs序上弄,对于i,选i+1就到i+1,不选直接到i+size[i+1]
现在我们想想多重背包,直接上会TLE。
首先一定要选,就是先强制放一个。
设剩余还有d个,假如d=2^0+2^1+……2^k+t
其中t<2^(k+1)
那么其实可以拆成现在有许多个物品,每种物品只有1个,然后做01背包。
假设原先物品价值为w价格为c
拆出的物品分别是价值为w*2^i价格为c*2^i。
还有一个w*t,c*t的。
于是就是这样。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=500+10,maxm=4000+10;
int f[maxn][maxm],g[maxm];
int h[maxn],go[maxn*2],next[maxn*2],dfn[maxn],a[maxn],size[maxn],w[maxn],c[maxn],d[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,tot,top,euler,ans,ca;
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void dfs(int x,int y){
top++;
int t=h[x];
size[x]=1;
while (t){
if (!bz[go[t]]&&go[t]!=y){
dfs(go[t],x);
size[x]+=size[go[t]];
}
t=next[t];
}
}
void dg(int x,int y){
a[++euler]=x;
size[x]=1;
int t=h[x];
while (t){
if (!bz[go[t]]&&go[t]!=y){
dg(go[t],x);
size[x]+=size[go[t]];
}
t=next[t];
}
}
void addin(int w,int c){
int i;
fd(i,m,c)
g[i]=max(g[i],g[i-c]+w);
}
void insert(int x,int w,int c,int d,int y){
if (c>m) return;
int i,j;
fo(i,0,m) g[i]=-100000000;
fo(i,0,m-c)
g[i+c]=f[x][i]+w;
d--;
if (d){
j=0;
while (1){
if ((1<<j)<=d){
addin(w*(1<<j),c*(1<<j));
d-=(1<<j);
}
else{
addin(w*d,c*d);
break;
}
j++;
}
}
fo(i,0,m) f[y][i]=max(f[y][i],g[i]);
}
void dp(){
if (c[a[1]]>m) return;
int i,j;
fo(i,1,top+1)
fo(j,0,m)
f[i][j]=-100000000;
fo(i,1,d[a[1]])
if (c[a[1]]*i<=m) f[1][c[a[1]]*i]=w[a[1]]*i;
fo(i,1,top){
if (i==top){
fo(j,0,m)
f[top+1][j]=max(f[top+1][j],f[i][j]);
break;
}
insert(i,w[a[i+1]],c[a[i+1]],d[a[i+1]],i+1);
fo(j,0,m) f[i+size[a[i+1]]][j]=max(f[i+size[a[i+1]]][j],f[i][j]);
}
fo(i,0,m) ans=max(ans,f[top+1][i]);
}
void solve(int x){
top=0;
dfs(x,0);
int j=x,k=0,t;
while (1){
t=h[j];
while (t){
if (!bz[go[t]]&&go[t]!=k&&size[go[t]]>top/2){
k=j;
j=go[t];
break;
}
t=next[t];
}
if (!t) break;
}
euler=0;
dg(j,0);
dp();
bz[j]=1;
t=h[j];
while (t){
if (!bz[go[t]]) solve(go[t]);
t=next[t];
}
}
int main(){
freopen("shopping.in","r",stdin);freopen("shopping.out","w",stdout);
ca=read();
while (ca--){
n=read();m=read();
fo(i,1,n) h[i]=0;
tot=0;
fo(i,1,n) w[i]=read();
fo(i,1,n) c[i]=read();
fo(i,1,n) d[i]=read();
fo(i,1,n-1){
j=read();k=read();
add(j,k);add(k,j);
}
fo(i,1,n) bz[i]=0;
ans=0;
solve(1);
printf("%d\n",ans);
}
}