题面
题意
给出一颗n个节点的树,每个节点的值有一个区间范围,问如何选取节点的值才能使这颗树变成完美的树,完美的树满足每条边所连接的两个节点的差值的绝对值之和最大
题解(树形DP)
我们知道,要想使两个节点的差值绝对值最大,那么这两个节点一定是去边界值,那么就变成了每个节点选左边界还是有边界
f [u] [0] : 表示 u 节点取左边界的值
f [u] [1] : 表示 u 节点取有边界的值
建树后,直接从根节点开始dfs即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll t, n;
ll lv[N], rv[N];
ll h[N], e[2 * N], ne[2 * N], idx;
ll f[N][2];
//添加一条 a-->b 的边
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int u, int father) {
f[u][0] = 0; //表示u节点取左边界
f[u][1] = 0; //表示u节点取右边界
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == father) continue;
dfs(j, u);
f[u][0] += max(f[j][0] + abs(lv[u] - lv[j]), f[j][1] + abs(lv[u] - rv[j]));
f[u][1] += max(f[j][0] + abs(rv[u] - lv[j]), f[j][1] + abs(rv[u] - rv[j]));
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
cin >> t;
while (t--) {
memset(h, -1, sizeof h);
idx = 0;
cin >> n;
for (int i = 1; i <= n; i++) cin >> lv[i] >> rv[i];
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a); //建立无向边
}
dfs(1, -1);
cout << max(f[1][0], f[1][1]) << endl;
}
return 0;
}