JZOJ4202. Shopping(點分治+樹形依賴+多重揹包)
阿新 • • 發佈:2019-01-26
題意:
- 一顆樹,每個點代表一個物品,空間,數量,價值,現有一個空間為的揹包,選樹上相互連線的物品,求最大價值
想法:
- 一眼樹形揹包,時間複雜度上天
- 表示i的子樹內,i必選一個,空間為j的最大價值
- 時間複雜度O()
- 由於選互相連線的物品,所以我們可以假定必須選某個點,然後做一次樹形依賴多重揹包,最後在遞迴到子樹內繼續找
- 那肯定是找樹的重心啊,所以遞迴成點分治
- 樹形依賴:由於要選某個點必須要選他的所有祖先,所以可以先做出序
- 設
- 選:
- 不選:
- 多重揹包
- 選d個的話
- 把它分成的形式,當01揹包做,每個物品即空間,價格
- 好像還有一種單調佇列的套路,找機會學一學
-時間複雜度(
#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);
}
}