1. 程式人生 > >BZOJ4182: Shopping(點分治,樹上揹包)

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

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 }