埋土 题解

\(dp(p,a,b)\) 表示 \(p\) 的子树中与它的父亲 \(f\) 联通的点的个数是 \(a\) , \(p\) 的上面与 \(f\) 联通的点的个数是 \(b\) 的最小损失,显然 \(a \ge 0,b \ge 1\)

\(p\) 没有儿子时:

\(dp(p,1,i)=iv,dp(p,0,i)=v^2\),其中 \(v\)\(p\)\(p\) 的父亲的边的边权。

\(p\) 的儿子只有一个 \(s\) 时:

如果 \(p\)\(p\) 的父亲不断开,显然 \(dp(p,i,j)=\min(dp(s,i-1,j+1)+i \times j \times v)\)

如果 \(p\)\(p\) 的父亲断开,\(dp(p,0,j)=\min(dp(s,i,1)+v^2)\)

\(p\) 的儿子有很多个时:

发现如果 \(p\)\(p\) 的父亲不断开,式子是 \(dp(p,i,j)=\min(\sum\limits_{s \in son_p}dp(s,k_s,l_s)+i \times j \times v)\),要求 \(\sum\limits_{s \in son_p}k_s+1=i,\sum\limits_{s \in son_p}k_s-k_t+j+1=l_t\)

枚举所有 \(k_s\)\(j\) 并求出所有 \(l_s\)\(i\) 显然复杂度爆炸。

可以再建一个子 dp \(f(s,a,b)\) 表示进行到 \(s\)\(\large{\sum\limits_{t=s_{first}}^sk_t=a,\sum\limits_{t=s_{next}}^{s_{last}}k_t+j+1=b}\)\(p\) 的上面有 \(j\) 个与它联通的点的 \(\large{\min(\sum\limits_{t\in son_p}^sdp(t,k_t,l_t))}\)

于是 \(f(s_{next},i+k,j-k)=\min(f(s,i,j)+dp(s_{next},k,i+j-k))\)

前面那一维可以滚掉,卡一下边界,可以发现 \(i\)\(k\) 的大小与树上背包的转移一致,再多枚举了一个 j,所以复杂度是 \(O(n^2 \times (<n))=O(<n^3)\)

于是如果 \(p\)\(p\) 的父亲不断开, \(dp(p,i,j)=\min(f(s_{last},i-1,j+1)+i \times j \times v)\)

如果 \(p\)\(p\) 的父亲断开,\(dp(p,0,j)=\min(f(s_{last},i,1)+v^2)\)

这和只有一个儿子时的转移一模一样。

但是单纯这样不能过,\(500^3\) 个 long long 的内存高达 1G,所以还要优化内存。

发现下面的 dp 处理完了之后就没用了,内存可以转移到上面,重链剖分一下,可以每条链共用一个 \(n^2\) 的内存,下面的处理完了继承到上面,在没处理完 f 时 dp 不能计算,所以可以把 f 用 dp 表示,这样最多用一个节点到根结点的链数个 \(n^2\) dp,内存是 \(O(n^2logn)\)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define long long long
int n,lt[510][510],sz[510],cs[510];
long dp[12][510][510],f[510][510],lv[510],res;
void dfs(int p){
	sz[p]=1;
	for(int i=0;i<cs[p];i++)dfs(lt[p][i]),sz[p]+=sz[lt[p][i]];
	sort(lt[p],lt[p]+cs[p],[](int a,int b){return sz[a]>sz[b];});
}
void cfs(int p,int o){
	if(cs[p]==0){
		for(int i=1;i<=n-1;i++)dp[o][1][i]=lv[p]*i,dp[o][0][i]=lv[p]*lv[p];
	}else{
		cfs(lt[p][0],o);
		int x=sz[lt[p][0]],y=n-sz[lt[p][0]];
		for(int _=1;_<cs[p];_++){
			cfs(lt[p][_],o+1);
			for(int i=0;i<=x+sz[lt[p][_]];i++)for(int j=1;j<=y-sz[lt[p][_]];j++)f[i][j]=1e18;
			for(int i=0;i<=x;i++)for(int j=1;j<=y;j++)for(int k=0;k<=sz[lt[p][_]]&&k<j;k++)
				f[i+k][j-k]=min(f[i+k][j-k],dp[o][i][j]+dp[o+1][k][i+j-k]);
			x+=sz[lt[p][_]],y-=sz[lt[p][_]];	
			for(int i=0;i<=x;i++)for(int j=1;j<=y;j++)dp[o][i][j]=f[i][j];
		}
		if(p==1){
			for(int i=0;i<=n-1;i++)res=min(res,dp[o][i][1]);
		}else{
			for(int i=0;i<=sz[p];i++)for(int j=1;j<=n-sz[p];j++)f[i][j]=1e18;
			for(int i=1;i<=sz[p];i++)for(int j=1;j<=n-sz[p];j++)
				f[i][j]=min(f[i][j],dp[o][i-1][j+1]+lv[p]*i*j);
			for(int i=0;i<=sz[p]-1;i++)f[0][1]=min(f[0][1],dp[o][i][1]+lv[p]*lv[p]);
			for(int i=2;i<=n-sz[p];i++)f[0][i]=f[0][1];
			for(int i=0;i<=sz[p];i++)for(int j=1;j<=n-sz[p];j++)dp[o][i][j]=f[i][j];
		}
	}
}
int main(){
	cin>>n,res=1e18;
	for(int i=2,a;i<=n;i++)cin>>a>>lv[i],lt[a][cs[a]++]=i;
	dfs(1),cfs(1,0),cout<<res;
	return 0;
}
#include<iostream>//不能过的内存 O(n^3)
#include<cstdio>//用vector节省空间实际也可以过
using namespace std;
#define long long long
int n,lt[510][510],sz[510],cs[510];
long dp[510][510][510],f[2][510][510],lv[510];
void cfs(int p){
	sz[p]=1;
	for(int i=0;i<cs[p];i++)cfs(lt[p][i]),sz[p]+=sz[lt[p][i]];
	if(cs[p]==0){
		for(int i=1;i<=n-1;i++)dp[p][1][i]=lv[p]*i,dp[p][0][i]=lv[p]*lv[p];
	}else{
		int b=1,x=sz[lt[p][0]],y=n-sz[lt[p][0]];
		for(int i=0;i<=x;i++)for(int j=1;j<=y;j++)f[b][i][j]=dp[lt[p][0]][i][j];
		for(int _=1;_<cs[p];_++){
			for(int i=0;i<=x+sz[lt[p][_]];i++)for(int j=1;j<=y-sz[lt[p][_]];j++)f[!b][i][j]=1e18;
			for(int i=0;i<=x;i++)for(int j=1;j<=y;j++)for(int k=0;k<=sz[lt[p][_]]&&k<j;k++)
				f[!b][i+k][j-k]=min(f[!b][i+k][j-k],f[b][i][j]+dp[lt[p][_]][k][i+j-k]);
			x+=sz[lt[p][_]],y-=sz[lt[p][_]],b=!b;
		}
		for(int i=1;i<=sz[p];i++)for(int j=1;j<=n-sz[p];j++)
			dp[p][i][j]=min(dp[p][i][j],f[b][i-1][j+1]+lv[p]*i*j);
		for(int i=0;i<=sz[p]-1;i++)dp[p][0][1]=min(dp[p][0][1],f[b][i][1]+lv[p]*lv[p]);
		for(int i=2;i<=n-sz[p];i++)dp[p][0][i]=dp[p][0][1];
	}
}
int main(){
	cin>>n;
	for(int i=2,a;i<=n;i++)cin>>a>>lv[i],lt[a][cs[a]++]=i;
	for(int i=1;i<=n;i++)for(int j=0;j<=n;j++)for(int k=0;k<=n;k++)dp[i][j][k]=1e18;
	cfs(1),cout<<dp[1][0][1];
	return 0;
}
posted @ 2026-06-08 18:31  Perfound  阅读(9)  评论(0)    收藏  举报