P2515 [HAOI2010]软件安装

https://www.luogu.com.cn/problem/P2515

考虑对 \(i\) 依赖 \(j\) 认为 \(j\)\(i\) 的父亲。那么就是图就是森林。对于一个点要搞它就必须搞这个点到链。

image
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;
}
posted @ 2022-07-22 20:37  FxorG  阅读(32)  评论(1编辑  收藏  举报