【题解】P9128 [USACO23FEB] Fertilizing Pastures G

零:前言

下位紫难度吧

\(link\)

壹:T=0

此时时间为 \(2*(n-1)\)

花费的话,我们贪心重排兄弟节点,然后dp处理

对于兄弟节点 \(u,v\)

先遍历 \(u\) 子树再遍历 \(v\) 子树,此时贡献为 \(E(u)+E(v)+siz(u)*sumA(v)\)

先遍历 \(v\) 子树再遍历 \(u\) 子树,此时贡献为 \(E(u)+E(v)+siz(v)*sumA(u)\)

取最小值,即 \(u<v,siz(u)*sumA(v)<=siz(v)*sumA(u)\) 得 \(u<v,siz(u)/sumA(u)<=siz(v)/sumA(v)\)

排序即可

然后 \(F\) 数组dp转移

贰:T=1

此时时间为 \(2*(n-1)-maxdep\)

对于花费,我们可以开一个 \(G\) 数组,每次把所有 \(=maxdep\) 的分别移到最右边,统计 \(G\) 最小值

当前节点 \(u\) ,儿子节点 \(v\)

\(suf\) 表示排序完毕时 \(v\) 后面的兄弟节点的 \(sumA\) 的和, \(len\) 表 \(siz\) 的和

\(G_u=min\{F_u-F_v-suf*siz_v*2+G_v+len*2*sumA_v\}\)

参:代码

#include<bits/stdc++.h>
#define inf 5e18
#define int long long
using namespace std;
const int N=2e5+10;
vector<int> mp[N];
int a[N];
int siz[N],sumA[N];
int dep[N],maxdep[N];
int fa[N];
void dfs1(int u,int pa){
	siz[u]=1;
	sumA[u]=a[u];
	fa[u]=pa;
	maxdep[u]=dep[u]=dep[pa]+1;
	for(auto v:mp[u]){
		dfs1(v,u);
		siz[u]+=siz[v];
		sumA[u]+=sumA[v];
		maxdep[u]=max(maxdep[u],maxdep[v]);
	}
}
int F[N],G[N];
bool cmp(int a,int b){
	return 1.0*siz[a]/sumA[a]<1.0*siz[b]/sumA[b];
}
void dfs2(int u){
	sort(mp[u].begin(),mp[u].end(),cmp);
	int s=0;
	for(auto v:mp[u]){
		dfs2(v);
		F[u]+=F[v]+(s+1)*sumA[v];
		s+=2*siz[v];
	}
}
void dfs3(int u){
	if(mp[u].size()) G[u]=inf;
	else G[u]=0;
	reverse(mp[u].begin(),mp[u].end());
	int len=0,suf=0;
	for(auto v:mp[u]){
		dfs3(v);
		if(maxdep[u]==maxdep[v]) G[u]=min(G[u],F[u]-F[v]+G[v]-suf*siz[v]*2+len*2*sumA[v]);
		suf+=sumA[v];
		len+=siz[v];
	}
	//cerr<<"-->"<<u<<" "<<G[u]<<"\n";
}
signed main(){
	int n,T;cin>>n>>T;
	for(int i=2;i<=n;i++){
		int f;cin>>f>>a[i];
		mp[f].push_back(i);
	}
	dfs1(1,0);
	dfs2(1);
	dfs3(1);
	if(T==0) cout<<2*(n-1)<<" "<<F[1]<<"\n";
	else cout<<2*(n-1)-maxdep[1]+1<<" "<<G[1]<<"\n";
	return 0;
} 
posted @ 2026-04-21 22:55  Aistyr  阅读(25)  评论(0)    收藏  举报