CF2062D Banlanced Tree *2200(结论+树形dp)

\[\begin{flalign*} &题意:给定一棵树,每个节点权值的范围是[l_i,r_i]\\& 你可以任意选择u,v使得以u为根v的子树加1&\\& 若干轮操作后,所有节点权值相等,问最小的全相等权值是多少?\\& 换根操作比较麻烦,考虑固定根节点为1,将换根操作转换成根为1的操作\\& 不换根的话就是子树加1,如果换了根的话,可以使得u子树以外的点全加1\\& 那么等价于全局加1,子树减1\\& 贪心的考虑,点权i初值设为l_i,那么每个点可以抵消r_i-l_i次全局加1操作\\& 定义f_i为使得子树全相等的最小[l_i,r_i]中的值,那么最后的答案是全局加次数+f_1 \end{flalign*} \]

const int N=2e5+10;
int l[N],r[N];
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>l[i]>>r[i];
	}
	vector<vector<int>>g(n+1);
	for(int i=1;i<n;i++){
		int u,v; cin>>u>>v;
		g[u].push_back(v),g[v].push_back(u);
	}
	int cnt=0;
	vector<int>f(n+1,0);
	auto dfs=[&](auto self,int u,int fa)->void{
		f[u]=l[u];
		for(auto v:g[u]){
			if(v==fa) continue;
			self(self,v,u);
			if(f[v]>f[u]){
				int temp=f[v]-f[u]-(r[u]-l[u]);
				if(temp>=0){
					l[u]=r[u];
				}
				else{
					l[u]+=f[v]-f[u];
				}
				cnt+=max(0ll,temp);
				f[u]=l[u];
			}
		}
	};
	dfs(dfs,1,0);
	cout<<f[1]+cnt<<endl;
}
posted @ 2025-04-02 20:37  肆惠  阅读(41)  评论(0)    收藏  举报