题目描述:
马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街。商店街有n个商店,并且它们之间的道路构成了一颗树的形状。
第i个商店只卖第i种物品,小苗对于这种物品的喜爱度是wi,物品的价格为ci,物品的库存是di。
但是商店街有一项奇怪的规定:如果在商店 u,v买了东西,并且有一个商店w在u到v的路径上,那么必须要在商店w买东西。
小葱身上有m元钱,他想要尽量让小苗开心,所以他希望最大化小苗对买到物品的喜爱度之和。
这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为OI选手的你,你能帮帮他吗?
题解:
我们可以发现,选择的一定是个联通块。
这就似乎是树上背包。
由于根不确定而且有依赖性,我们可以通过点分治的性质优化背包。
有点恶心。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 550 #define M 4050 inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int T,n,m,hed[N],cnt; int w[N],c[N],d[N]; struct EG { int to,nxt; }e[2*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } int mrk[N],ans; int rt,v[N],siz[N],sum; void get_rt(int u,int fa) { v[u] = 0,siz[u] = 1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==fa||mrk[to])continue; get_rt(to,u); siz[u]+=siz[to]; if(siz[to]>v[u])v[u]=siz[to]; } v[u] = max(v[u],sum-siz[u]); if(v[u]<v[rt])rt=u; } int f[N][M]; void dfs(int u,int fa,int lim) { if(lim<=0)return ; int i,j; for(i=1,j=d[u];i<j;j-=i,i<<=1) for(int k=lim;k>=i*c[u];k--) f[u][k] = max(f[u][k],f[u][k-i*c[u]]+i*w[u]); for(int k=lim;k>=j*c[u];k--) f[u][k] = max(f[u][k],f[u][k-j*c[u]]+j*w[u]); for(j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to]||to==fa)continue; for(i=0;i<=lim-c[to];i++)f[to][i]=f[u][i]+w[to]; dfs(to,u,lim-c[to]); for(i=0;i<=lim-c[to];i++)f[u][i+c[to]]=max(f[u][i+c[to]],f[to][i]); } } void work(int u) { mrk[u] = 1; for(int i=0;i<=m-c[u];i++)f[u][i] = w[u]; dfs(u,0,m-c[u]); for(int i=0;i<=m-c[u];i++)ans = max(ans,f[u][i]); int sm0 = sum; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to])continue; rt=0,sum=(siz[to]>siz[u]?sm0-siz[u]:siz[to]); get_rt(to,0); work(rt); } } void init() { cnt=ans=0; memset(hed,0,sizeof(hed)); memset(mrk,0,sizeof(mrk)); } int main() { // freopen("1.in","r",stdin); T = rd(); v[0]=0x7fffffff; while(T--) { init(); n = rd(),m = rd(); for(int i=1;i<=n;i++)w[i]=rd(); for(int i=1;i<=n;i++)c[i]=rd(); for(int i=1;i<=n;i++)d[i]=rd()-1; for(int f,t,i=1;i<n;i++) { f=rd(),t=rd(); ae(f,t),ae(t,f); } rt=0,sum=n; get_rt(1,0); work(rt); printf("%d ",ans); } return 0; }