【BZOJ4182: Shopping】静态点分治+依赖树形多重背包
我可能原本对于多重背包的二进制分组有所误解orz orz orz
4182: Shopping
Time Limit: 30 Sec Memory Limit: 128 MB Submit: 500 Solved: 177 [Submit][Status][Discuss]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
HINT
N<=500,M<=4000,T<=5,Wi<=4000,Di<=100
Source
题意大概就是,找出一个最大的当根的点的最大树形依赖多重背包的。 于是乎对于换根考虑,我们静态点分治解决之。对于树形背包有一个dfs序的背包方式: F[i][j] 考虑完dfs序为i,i+1,i+2.....n的所有点后,背包容量为j的最大贡献。转移选和不选,选的话就考虑选不选子树否则就跳过这一段dfs序。 如果对于普通0/1树形依赖背包的转移方程f[i][j] = max: f[i+1][j-1]+V[i] , f[i+siz[i]][j] 而对于本题还有物品限制。我们利用二进制分组一下,把物品拆分,如7我们拆成1,2,4,,如9我们拆成1,2,4,2。也就是前面我们尽可能用2的次幂去填,不够了就直接留下最后那一段。可以想到这样是可以完全将所有物品的个数的情况考虑到的。 时间复杂度(O(Tnm*log2 di * log2 n) code:#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 505;
const int maxm = 4005;
int n,m; bool vis[maxn];
int w[maxn],c[maxn],d[maxn],sz[maxn];//jiage chengben shuliang
int en[maxn*2],nt[maxn*2],la[maxn],owo;
void adg(int x,int y) {
en[++owo]=y; nt[owo]=la[x]; la[x]=owo;
}
using namespace std;
int RT,rtsz,sm,ANS;
int f[maxn][maxm];
void frt(int x,int ba) {
sz[x]=1; int ss=0;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(y==ba||vis[y]) continue;
frt(y,x);
sz[x]+=sz[y]; ss=max(ss,sz[y]);
} ss=max(sm-sz[x],ss);
if(ss<rtsz) rtsz=ss,RT=x;
}
int dy[maxn],dfx;
void dfs(int x,int ba) {
dy[++dfx] = x; sz[x]=1;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(y==ba||vis[y]) continue;
dfs(y,x);
sz[x] += sz[y];
}
}
void calc(int x) {
dfx=0; dfs(x,0);
for(int i=dfx;i>=1;i--) {
int k = dy[i];
for(int j=1;j<=m;j++) f[i][j] = f[i+sz[k]][j];
int od = 1; int oz = d[k];
for(;od<=oz;od<<=1) {
oz-=od;
for(int j=m;j>=od*c[k];j--) {
int cost = od*c[k]; int vv = od*w[k];
f[i][j] = max(f[i][j], max(f[i][j-cost]+vv,f[i+1][j-cost]+vv));
}
}
if(oz>0) {
for(int j=m;j>=oz*c[k];j--) {
int cost = oz*c[k]; int vv = oz*w[k];
f[i][j] = max(f[i][j], max(f[i][j-cost]+vv,f[i+1][j-cost]+vv));
}
}
}
ANS = max(ANS,f[1][m]);
for(int i=1;i<=dfx;i++) {
for(int j=0;j<=m;j++) f[i][j]=0;
}
}
void work(int x) {
calc(x); vis[x] = 1;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(vis[y]) continue;
sm = sz[y]; rtsz = 0x3f3f3f3f; frt(y,x);
work(RT);
}
}
void solve() {
scanf("%d%d",&n,&m);
owo = ANS = 0;
for(int i=1;i<=n;i++) la[i] = vis[i] = 0;
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++) scanf("%d",&d[i]);
for(int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
adg(x,y); adg(y,x);
}
sm=n; rtsz=0x3f3f3f3f; frt(1,0);
work(RT);
printf("%d\n",ANS);
}
int main() {
int T;
scanf("%d",&T);
while(T--) solve();
}

浙公网安备 33010602011771号