P2515 [HAOI2010]软件安装
https://www.luogu.com.cn/problem/P2515
考虑对 \(i\) 依赖 \(j\) 认为 \(j\) 是 \(i\) 的父亲。那么就是图就是森林。对于一个点要搞它就必须搞这个点到链。
22.cnblogs.com/blog/1910062/202207/1910062-20220722203459948-261045732.png)
因为儿子共用 \(x->root\) 这条链,所以我们可以对于儿子都不收费最后再整体收一次费(因为要求 x 一定选),也就是最后再来值域向右平移即可。
注意下可能有环,当复习 tarjan 了。
最后森林对于每棵树合并下即可。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
int rd() {
int sum=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0') {
sum=sum*10+ch-'0'; ch=getchar();
}
return sum*f;
}
const int N=105,M=(int)(1e5+5),MX=(int)(1e3);
vector<int>g[N];
int f[N][M],tmp[M],a[N],b[N],w[N],v[N],fa[N],n,m;
void dfs(int x,int W) {
for(int i=0;i<g[x].size();i++) {
int y=g[x][i];
dfs(y,W+w[x]);
int Wy=W+w[x];
for(int j=2*MX;j>=0;j--) {
for(int k=0;k<=j;k++) {
if(k+Wy>MX) break ;
f[x][j]=max(f[x][j],f[y][k+Wy]+f[x][j-k]);
}
}
}
for(int i=0;i<=2*MX;i++) tmp[i]=f[x][i];
for(int i=0;i<=2*MX;i++) {
if(i-W-w[x]>=0) f[x][i]=tmp[i-W-w[x]]+v[x];
else f[x][i]=0;
}
}
int ff[M];
bool flag[N];
int dfn[N],low[N],id[N],tot,col;
stack<int>s;
void tarjan(int x) {
dfn[x]=low[x]=++tot;
s.push(x); flag[x]=1;
for(int i=0;i<g[x].size();i++) {
int y=g[x][i];
if(!dfn[y]) {
tarjan(y); low[x]=min(low[x],low[y]);
} else if(flag[y]) {
low[x]=min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x]) {
++col;
while(1) {
int qwq=s.top(); s.pop();
id[qwq]=col; flag[qwq]=0; if(qwq==x) break ;
}
}
}
int du[N];
signed main() {
n=rd(); m=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++) b[i]=rd();
for(int i=1;i<=n;i++) {
fa[i]=rd(); if(fa[i]) g[fa[i]].pb(i);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<=n;i++) {
if(!fa[i]) continue ;
if(id[i]!=id[fa[i]]) g[id[fa[i]]].pb(id[i]),++du[id[i]];
}
// for(int i=1;i<=n;i++) cout<<id[i]<<'\n';
for(int i=1;i<=n;i++) w[id[i]]+=a[i],v[id[i]]+=b[i];
for(int i=1;i<=col;i++) if(!du[i]) dfs(i,0);
for(int i=1;i<=col;i++) {
if(!du[i])
for(int j=m;j>=0;j--) {
for(int k=0;k<=j;k++) {
ff[j]=max(ff[j],f[i][k]+ff[j-k]);
}
}
}
cout<<ff[m];
return 0;
}