BZOJ4182: Shopping(点分治,树上背包)
Description
马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街。商店街有n个商店,并且它们之间的道路构成了一颗树的形状。
第i个商店只卖第i种物品,小苗对于这种物品的喜爱度是wi,物品的价格为ci,物品的库存是di。但是商店街有一项奇怪的规定:如果在商店u,v买了东西,并且有一个商店w在u到v的路径上,那么必须要在商店w买东西。小葱身上有m元钱,他想要尽量让小苗开心,所以他希望最大化小苗对买
到物品的喜爱度之和。这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为OI选手的你,你能帮帮他吗?
Input
输入第一行一个正整数T,表示测试数据组数。
对于每组数据,
第一行两个正整数n;m;
第二行n个非负整数w1,w2...wn;
第三行n个正整数c1,c2...cn;
第四行n个正整数d1,d2...dn;
接下来n-1行每行两个正整数u;v表示u和v之间有一条道路
Output
输出共T 行,每行一个整数,表示最大的喜爱度之和。
Sample Input
1
3 2
1 2 3
1 1 1
1 2 1
1 2
1 3
3 2
1 2 3
1 1 1
1 2 1
1 2
1 3
Sample Output
4
解题思路:
可以发现答案最后是一颗子树,所以我们只需要枚举子树就好了,由于根节点不定,所以靠点分治来实现枚举根(如果答案比一个子树大,那么一点会经过这个根),Dfs序跑出来做树形背包就好了。
多重背包二进制拆分一下就好了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 const int N=510; 6 const int M=4010; 7 struct pnt{ 8 int hd; 9 int wgt; 10 int w; 11 int c; 12 int d; 13 int ind; 14 int oud; 15 bool vis; 16 }p[N],stp; 17 struct ent{ 18 int twd; 19 int lst; 20 }e[N<<1]; 21 int T,n,m; 22 int cnt; 23 int dfn; 24 int size; 25 int root; 26 int maxsize; 27 lnt ans; 28 int lin[N]; 29 lnt dp[N][M]; 30 void ade(int f,int t) 31 { 32 cnt++; 33 e[cnt].twd=t; 34 e[cnt].lst=p[f].hd; 35 p[f].hd=cnt; 36 return ; 37 } 38 void grc_dfs(int x,int f) 39 { 40 p[x].wgt=1; 41 int maxs=-1; 42 for(int i=p[x].hd;i;i=e[i].lst) 43 { 44 int to=e[i].twd; 45 if(to==f||p[to].vis) 46 continue; 47 grc_dfs(to,x); 48 p[x].wgt+=p[to].wgt; 49 if(maxs<p[to].wgt) 50 maxs=p[to].wgt; 51 } 52 maxs=std::max(maxs,size-p[x].wgt); 53 if(maxs<maxsize) 54 { 55 root=x; 56 maxsize=maxs; 57 } 58 return ; 59 } 60 void Build_dfs(int x,int f) 61 { 62 lin[++dfn]=x; 63 p[x].ind=dfn; 64 for(int i=p[x].hd;i;i=e[i].lst) 65 { 66 int to=e[i].twd; 67 if(to==f||p[to].vis) 68 continue; 69 Build_dfs(to,x); 70 } 71 p[x].oud=dfn; 72 return ; 73 } 74 void bin_dfs(int x) 75 { 76 p[x].vis=true; 77 dfn=0; 78 Build_dfs(x,x); 79 for(int i=0;i<=dfn+1;i++) 80 for(int j=0;j<=m;j++) 81 dp[i][j]=0; 82 for(int i=dfn;i;i--) 83 { 84 int t=lin[i]; 85 int w=p[t].d-1; 86 for(int j=m;j>=p[t].c;j--) 87 dp[i][j]=dp[i+1][j-p[t].c]+p[t].w; 88 for(int j=1;;j<<=1) 89 { 90 if(w<j) 91 j=w; 92 for(int k=m;k>=j*p[t].c;k--) 93 dp[i][k]=std::max(dp[i][k],dp[i][k-j*p[t].c]+j*p[t].w); 94 w-=j; 95 if(!w) 96 break; 97 } 98 for(int j=0;j<=m;j++) 99 dp[i][j]=std::max(dp[i][j],dp[p[t].oud+1][j]); 100 } 101 ans=std::max(ans,dp[1][m]); 102 for(int i=p[x].hd;i;i=e[i].lst) 103 { 104 int to=e[i].twd; 105 if(p[to].vis) 106 continue; 107 root=0; 108 size=p[to].wgt; 109 maxsize=0x3f3f3f3f; 110 grc_dfs(to,to); 111 bin_dfs(root); 112 } 113 return ; 114 } 115 int main() 116 { 117 //freopen("a.in","r",stdin); 118 scanf("%d",&T); 119 while(T--) 120 { 121 scanf("%d%d",&n,&m); 122 for(int i=1;i<=n;i++) 123 p[i]=stp; 124 cnt=0,ans=0; 125 for(int i=1;i<=n;i++) 126 scanf("%d",&p[i].w); 127 for(int i=1;i<=n;i++) 128 scanf("%d",&p[i].c); 129 for(int i=1;i<=n;i++) 130 scanf("%d",&p[i].d); 131 for(int i=1;i<n;i++) 132 { 133 int a,b; 134 scanf("%d%d",&a,&b); 135 ade(a,b); 136 ade(b,a); 137 } 138 root=0; 139 size=n; 140 maxsize=0x3f3f3f3f; 141 grc_dfs(1,1); 142 bin_dfs(root); 143 printf("%lld\n",ans); 144 } 145 return 0; 146 }