题意:
- 一颗树,每个点代表一个物品,空间c[i]c[i],数量d[i]d[i],价值w[i]w[i],现有一个空间为mm的背包,选树上相互连接的物品,求最大价值
想法:
- 一眼树形背包,时间复杂度上天
- f[i][j]表示i的子树内,i必选一个,空间为j的最大价值
- 时间复杂度O(n2m2dn2m2d)
- 由于选互相连接的物品,所以我们可以假定必须选某个点,然后做一次树形依赖多重背包,最后在递归到子树内继续找
- 那肯定是找树的重心啊,所以递归成点分治
- 树形依赖:由于要选某个点必须要选他的所有祖先,所以可以先做出dfndfn序
- 设i=dfn[x]i=dfn[x]
- 选:f[i+1][y]=max(f[i+1][y],f[i][y−c[x]]+w[x])f[i+1][y]=max(f[i+1][y],f[i][y−c[x]]+w[x])
- 不选:f[i+siz[x]+1][y]=max(f[i+siz[x]+1][y],f[i][y])f[i+siz[x]+1][y]=max(f[i+siz[x]+1][y],f[i][y])
- 多重背包
- 选d个的话
- 把它分成1+2+4+,,,,,+2n+y1+2+4+,,,,,+2n+y的形式,当01背包做,每个物品即空间c[i]∗2nc[i]∗2n,价格w[i]∗2nw[i]∗2n
- 好像还有一种单调队列的套路,找机会学一学
-时间复杂度(nlognmlogdnlognmlogd)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define fb(i,x) for(i=last[x];i;i=next[i])
const int maxN=510,maxM=4010,maxn=-1e9;
using namespace std;
bool bz[maxN],broke[maxN];
int t,n,m,tot,i,w[maxN],c[maxN],d[maxN],f[maxN][maxM],last[maxN],
tov[maxN*2],next[maxN*2],pre[maxN],h[maxM],cnt,siz[maxN],
ans,x,y,cm[maxN],fa[maxN];
void insert(int x,int y){
tov[++tot]=y,next[tot]=last[x],last[x]=tot;
}
void dfss(int x){
int i,y;
bz[x]=true,pre[++cnt]=x,siz[x]=1;
fb(i,x){
y=tov[i];
if (!bz[y] && !broke[y]) dfss(y),siz[x]+=siz[y],fa[y]=x;
}
}
void find_ans(){
int x,i,j,xx,yy,k;
fo(i,1,cnt+1)
fo(j,0,m) f[i][j]=maxn;
f[1][0]=0;
fo(i,1,cnt){
x=pre[i];
fo(j,0,m) h[j]=maxn;
fo(j,c[x],m)
if (f[i][j-c[x]]!=maxn)h[j]=f[i][j-c[x]]+w[x];
y=d[x]-1;
fo (j,0,7){
if (y<cm[j]) break;
xx=cm[j]*w[x],yy=cm[j]*c[x];
fd(k,m,yy)
if (h[k-yy]!=maxn) h[k]=max(h[k],h[k-yy]+xx);
y-=cm[j];
}
xx=y*w[x],yy=y*c[x];
fd(j,m,yy)
if (h[j-yy]!=maxn) h[j]=max(h[j],h[j-yy]+xx);
fo(j,c[x],m) f[i+1][j]=max(f[i+1][j],h[j]);
fo(j,0,m)
f[i+siz[x]][j]=max(f[i+siz[x]][j],f[i][j]);
}
fo(i,0,m)
ans=max(ans,f[cnt+1][i]);
}
void dfs(int x){
int j,cut=0,yy,i;
bool bz1;
cnt=0,dfss(x);
fo(i,1,cnt){
yy=pre[i],bz1=true;
if (cnt-siz[yy]>cnt/2) continue;
fb(j,yy)
if (siz[tov[j]]>cnt/2 && tov[j]!=fa[yy] && !broke[tov[j]]) {bz1=false;
break;
}
if (bz1){
cut=yy;
break;
}
}
broke[cut]=true;
fo(i,1,cnt)
siz[pre[i]]=0,bz[pre[i]]=false,fa[pre[i]]=0;
cnt=0,dfss(cut);
find_ans();
fo(i,1,cnt)
siz[pre[i]]=0,bz[pre[i]]=false,fa[pre[i]]=0;
fb(i,cut){
yy=tov[i];
if (!broke[yy]) dfs(yy);
}
}
int main(){
freopen("shopping.in","r",stdin);
freopen("shopping.out","w",stdout);
cm[0]=1;
fo(i,1,7) cm[i]=cm[i-1]*2;
for (scanf("%d",&t);t;t--){
mem(last,0),mem(bz,false),mem(broke,false),tot=0;
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d",&w[i]);
fo(i,1,n) scanf("%d",&c[i]);
fo(i,1,n) scanf("%d",&d[i]);
fo(i,1,n-1) scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
ans=0;
dfs(1);
printf("%d\n",ans);
}
}