我们先Tarjan 缩点 , 然后树形背包
我们令f[u][i] 表示点u及儿子选i个的最大价值
我们发现如果要加上儿子的贡献 , 当前点u必须选
因为u必须选 , 所以j只能枚举到i-w[u]
DP方程固然重要 , 范围也很重要
化学方程式固然重要 , 反应条件 , 气体符号 , 沉淀符号也很重要
#include<bits/stdc++.h>
#define N 105
#define M 505
using namespace std;
int w[N],v[N],ww[N],vv[N],n,m;
int du[N],f[N][M],rt,siz[N];
vector<int> V[N];
int first[N],next[N*2],to[N*2],tot;
int dfn[N],low[N],sta[N];
int top,insta[N],id[N],sign,cnt;
void add(int x,int y){
next[++tot]=first[x],first[x]=tot,to[tot]=y;
}
void dfs(int u){
low[u] = dfn[u] = ++sign;
sta[++top] = u , insta[u] = 1;
int siz = V[u].size()-1;
for(int i=0;i<=siz;i++){
int t=V[u][i];
if(!dfn[t]) dfs(t),low[u] = min(low[u],low[t]);
else if(insta[t] && dfn[t]<low[u]) low[u] = dfn[t];
}
if(dfn[u]==low[u]){
cnt++; do{
insta[sta[top]] = 0; id[sta[top]] = cnt;
ww[cnt] += w[sta[top]]; vv[cnt] += v[sta[top]];
} while(sta[top--]!=u);
}
}
void DP(int u,int fa){
siz[u] = ww[u];
for(int i=ww[u];i<=m;i++) f[u][i] = vv[u];
for(int i=first[u];i;i=next[i]){
int t=to[i]; if(t==fa) continue;
DP(t,u); siz[u] += siz[t];
for(int j=m;j>=ww[u];j--) for(int k=0;k<=j-ww[u];k++)
f[u][j] = max(f[u][j],f[t][k]+f[u][j-k]);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
for(int i=1;i<=n;i++){
int x; scanf("%d",&x);
if(x) V[x].push_back(i);
}
for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
for(int i=1;i<=n;i++){ int siz = V[i].size()-1;
for(int j=0;j<=siz;j++){ int t=V[i][j];
if(id[t]!=id[i]) du[id[t]]++,add(id[i],id[t]),add(id[t],id[i]);
}
}
for(int i=1;i<=cnt;i++) if(!du[i]) add(rt,i);
DP(rt,0); printf("%d",f[rt][min(m,siz[rt])]); return 0;
}