CF1528A div1 Parsa's Humongous Tree

题目传送门


题意

给定一棵树,每个点有一个l和r, 现在要给每个点(x)加一个权值(a_x),满足(l_x leq a_x leq r_x)
定义一棵树的权值为任意两个相邻节点u,v的权值差的绝对值之和, 即(sum_{u, v}|a_u-a_v|)(u,v相邻)
求这棵树的最大权值


题解

容易猜想每个点要么取最小值, 要么取最大值, 如何证明呢?
假设一个x取了a, (l_x < a < r_x)
与其相邻的两个点分别取了u, v
那么假如 (a<u,a<v), (l_x)显然更优
同理 (a>u, a>v), (r_x)更优
对于(u < a < v), (l_x, r_x)显然不劣
结论成立

然后就是套路dp了
dpi,0表示这个点取最小值时的最大值, dpi,1表示取最大值时的最大值
(dp_{v,0}+=max(dp_{u,0}+|lv−lu|,dp_{u,1}+|lv−ru|))
(dp_{v,1}+=max(dp_{u,0}+|rv−lu|,dp_{u,1}+|rv−ru|))


实现

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#define ll long long
using namespace std;

int read(){
	int num=0, flag=1; char c=getchar();
	while(!isdigit(c) && c!='-') c=getchar();
	if(c=='-') flag=-1, c=getchar();
	while(isdigit(c)) num=num*10+c-'0', c=getchar();
	return num*flag;
}

const int N = 210005;
int T, n;
int l[N], r[N];
ll f[N][2];
vector<int> p[N];

void dp(int x, int fa){
	for(int i=0; i<p[x].size(); i++){
		int nex = p[x][i];
		if(nex == fa) continue;
		
		dp(nex, x);
		f[x][0] += max(f[nex][0]+abs(l[x]-l[nex]), f[nex][1]+abs(l[x]-r[nex]));
		f[x][1] += max(f[nex][0]+abs(r[x]-l[nex]), f[nex][1]+abs(r[x]-r[nex]));
 	}
}

int main(){
	T = read();
	while(T--){
		n = read();
		for(int i=1; i<=n; i++) l[i]=read(), r[i]=read(), f[i][0]=f[i][1]=0, p[i].clear();
		for(int i=1; i<=n-1; i++) {
			int u=read(), v=read();
			p[u].push_back(v);
			p[v].push_back(u);
		}
		
		dp(1, 0);
		cout << max(f[1][0], f[1][1]) << endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/ltdjcoder/p/15329136.html