首页 > 其他分享 >P9128 [USACO23FEB] Fertilizing Pastures G

P9128 [USACO23FEB] Fertilizing Pastures G

时间:2023-03-09 23:11:30浏览次数:30  
标签:Pastures int res vec1 Fertilizing vec ed P9128 dp

咋没人写题解/fn

考虑行走的过程跟你 dfs 一棵树的过程是等价的,所以 \(T=0\) 时走的边数为 \(2(n-1)\),\(T=1\) 时,当遍历完最后一个点 \(x\) 时,不用再回溯到 \(1\),因此少了 \(dep_x\) 的时间。

那么你一旦进去一个点,你不走完它子树内的所有结点,它一定不会出来,倘若未走完就出来,则时间花费一定更劣。

考虑 \(T=0\) 时咋做,记 \(dp(x)\) 从 \(x\) 出发走完 \(x\) 子树并回到 \(x\) 的最小花费,显然你要安排各个儿子间的顺序,记其为序列 \(p\),使得 \(\sum\limits_{i=1}dp(p_i)+sum(p_i)\sum\limits_{1\le j<i}2(sz_{p_j}+1)\) 最小,即一定是走第一个儿子,然后出来,此时第二个儿子的时间点就多了第一个走进去又走出来的时间。这种往往可以考虑单独拎两个考虑在 \(p\) 中的先后关系,你假设 \(x\) 先还是 \(y\) 先然后分别计算其贡献即可。又因为你这个偏序关系有传递性,所以你直接 sort 就是对的。需要注意的是,当你当前考虑的子树根不为 \(1\) 的时候,你应该设其初始时间为 \(1\),这样你从父亲从儿子转移的时候才好转移,因为会经过一条边。而注意当考虑 \(1\) 的时候,初始时间应设为 \(0\)。这样设立的原因其实还有一点是你当根不为 \(1\) 时,你需要在根花费 1 单位时间。不这样的话,你可以不降 \(a_x\) 计入 \(dp_x\) 同样也可以做。

考虑 \(T=1\),显然还是类似,只不过你一定存在一个点,使得它在它的祖先当中永远是最后走的。这个点需要满足其深度最深。当然,显然这个点不唯一。因此你要把这个点贪出来。具体的,在当前树根为 \(x\) 时,记当前有资格最后走的点集为 \(S\),那么你不是最后走的你内部不必钦定最后走的点,只需按 \(T=0\) 的做法做即可。所以同样的,拎出 \((a,b)\) 进行比较即可。

总结,这类贪心确定排列顺序问题往往可以通过点对间的偏序来确定,因此分析的时候可以考虑一对,然后计算极端情况贡献,即仅考虑当前序列只有这两个元素,这两个元素的先后各自的贡献。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(2e5+5);
vector<int>g[N];
int n,T,t[N],sz[N],dp[N],a[N];

bool cmp(int x,int y) {
	return (t[x]+2)*a[y]<(t[y]+2)*a[x];
}

void dfs(int x) {
	sz[x]=1; dp[x]=a[x];
	for(int y:g[x]) {
		dfs(y); sz[x]+=sz[y]; a[x]+=a[y];
	}
	t[x]=2*(sz[x]-1);
	sort(g[x].begin(),g[x].end(),cmp);
	int res=1;
	if(x==1) res=0;
	for(int y:g[x]) {
		dp[x]=dp[x]+res*a[y]+dp[y];
		res+=t[y]+2;
	}
}

int dep[N],mx[N],dp2[N];
void dfsmxd(int x) {
	mx[x]=dep[x];
	for(int y:g[x]) {
		dep[y]=dep[x]+1;
		dfsmxd(y);
		mx[x]=max(mx[x],mx[y]);
	}
}
int ed;
bool cmpp(int x,int y) {
	return (t[x]+2)*a[y]+dp2[x]+dp[y]<(t[y]+2)*a[x]+dp2[y]+dp[x];
}
vector<int>vec1[N];
void dfs2(int x) {
	sz[x]=1; dp[x]=dp2[x]=a[x];
	for(int y:g[x]) {
		dfs2(y); sz[x]+=sz[y]; a[x]+=a[y];
	}
	t[x]=2*(sz[x]-1);
	for(int y:g[x]) {
		if(mx[y]==mx[1]) vec1[x].pb(y);
	}
	sort(vec1[x].begin(),vec1[x].end(),cmpp);
	ed=0;
	if(!vec1[x].empty()) ed=vec1[x].back();
	vector<int>vec; vec.clear();
	for(int y:g[x]) if(y!=ed) vec.pb(y); 
	sort(vec.begin(),vec.end(),cmp);
	int res=1;
	if(x==1) res=0;
	for(int y:vec) {
		dp[x]=dp[x]+res*a[y]+dp2[y];
		res+=t[y]+2;
	}
	if(ed) dp[x]=dp[x]+res*a[ed]+dp[ed];
	res=1; if(x==1) res=0;
	sort(g[x].begin(),g[x].end(),cmp);
	for(int y:g[x]) {
		dp2[x]+=res*a[y]+dp2[y];
		res+=t[y]+2;
	} 
}

signed main() {
//	freopen("11.in","r",stdin);
	cin.tie(0); ios::sync_with_stdio(false);
	cin>>n>>T;
	for(int i=2;i<=n;i++) {
		int x; cin>>x>>a[i];
		g[x].pb(i);
	}
	if(T==0) {
		dfs(1);
		cout<<2*n-2<<" "<<dp[1];
	} else {
		dfsmxd(1);
		cout<<2*n-2-mx[1]<<" ";
		dfs2(1);
		cout<<dp[1];
	}
	return 0; 
}

标签:Pastures,int,res,vec1,Fertilizing,vec,ed,P9128,dp
From: https://www.cnblogs.com/xugangfan/p/17201871.html

相关文章