题意
给一颗(n)个点的树,对于结点(i),你要给它标上一个([l_i,r_i])之间的数,要求所有边两端节点上标的数字的差的绝对值的总和最大
解法
首先要有一个贪心的思路:
对于一个点(x),它选择的权值一定是(l_x)或(r_x)
为什么会这样呢?意会一下证明
对于一个点,如果与它相连的点填的数都已经确定了,这些数会把该点的([l,r])区间划分成一个个小区间。我们能发现,该点往两边填一定会比往中间填更优
有了这个贪心思想,就可以进行(DP)了
转移方程很简单
代码
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
long long read();
int T, n;
int cap;
int head[N], to[N << 1], nxt[N << 1];
long long l[N], r[N], f[N][2];
template<typename _T>
inline void read(_T &x) {
x = 0; int c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
}
inline void add(int x, int y) {
to[++cap] = y, nxt[cap] = head[x], head[x] = cap;
}
inline long long max(long long x, long long y) {
return x > y ? x : y;
}
inline long long abs(long long x) {
return x < 0 ? -x : x;
}
void DFS(int x, int fa) {
for (int i = head[x]; i; i = nxt[i]) {
if (to[i] == fa) continue;
DFS(to[i], x);
f[x][1] += max(f[to[i]][1] + abs(r[x] - r[to[i]]), f[to[i]][0] + abs(r[x] - l[to[i]]));
f[x][0] += max(f[to[i]][0] + abs(l[to[i]] - l[x]), f[to[i]][1] + abs(r[to[i]] - l[x]));
}
}
int main() {
read(T);
while (T--) {
cap = 0;
memset(head, 0, sizeof head);
memset(f, 0, sizeof f);
read(n);
int x, y;
for (int i = 1; i < n; ++i) {
read(x), read(y);
add(x, y), add(y, x);
}
for (int i = 1; i <= n; ++i) read(l[i]), read(r[i]);
DFS(1, 0);
printf("%lld
", max(f[1][1], f[1][0]));
}
return 0;
}