Loading

Codeforces Round #722 (Div. 2) C. Parsa's Humongous Tree(树形DP)

Parsa has a humongous tree on 𝑛n vertices.

On each vertex 𝑣v he has written two integers 𝑙𝑣lv and 𝑟𝑣rv.

To make Parsa's tree look even more majestic, Nima wants to assign a number 𝑎𝑣av (𝑙𝑣≤𝑎𝑣≤𝑟𝑣lv≤av≤rv) to each vertex 𝑣v such that the beauty of Parsa's tree is maximized.

Nima's sense of the beauty is rather bizarre. He defines the beauty of the tree as the sum of |𝑎𝑢−𝑎𝑣||au−av| over all edges (𝑢,𝑣)(u,v) of the tree.

Since Parsa's tree is too large, Nima can't maximize its beauty on his own. Your task is to find the maximum possible beauty for Parsa's tree.

Input

The first line contains an integer 𝑡t (1≤𝑡≤250)(1≤t≤250) — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer 𝑛n (2≤𝑛≤105)(2≤n≤105) — the number of vertices in Parsa's tree.

The 𝑖i-th of the following 𝑛n lines contains two integers 𝑙𝑖li and 𝑟𝑖ri (1≤𝑙𝑖≤𝑟𝑖≤109)(1≤li≤ri≤109).

Each of the next 𝑛−1n−1 lines contains two integers 𝑢u and 𝑣v (1≤𝑢,𝑣≤𝑛,𝑢≠𝑣)(1≤u,v≤n,u≠v) meaning that there is an edge between the vertices 𝑢uand 𝑣v in Parsa's tree.

It is guaranteed that the given graph is a tree.

It is guaranteed that the sum of 𝑛n over all test cases doesn't exceed 2⋅1052⋅105.

Output

For each test case print the maximum possible beauty for Parsa's tree.

大意就是要给一棵树每个点赋值一个点权(有范围),使得每相邻两个点的点权差的绝对值之和最大。

首先很重要的一点就是这个范围其实没有用,点权要么是左端点要么是右端点。证明如下:

反证法,不妨设点权\(l < a[x] < r\),设与其相邻的点点权比他大的有p个,比他小的有q个,且p > q,那么a[x]取l一定比现在更优,因为这么移动对于p个点一定是正贡献,又因为p大于q,因此贡献一定是正数。p < q证法同理。

因此可以采用树形dp,设\(dp[i][j]\)表示i取左端点/右端点时以他为根整棵子树的相邻结点权值差绝对值的和,转移方程如下:

	dp[x][0] += 1ll * max(dp[y][0] + abs(l[x] - l[y]), dp[y][1] + abs(l[x] - r[y]));
	dp[x][1] += 1ll * max(dp[y][0] + abs(r[x] - l[y]), dp[y][1] + abs(r[x] - r[y]));

最后输出\(max(dp[1][0], dp[1][1])\)即可。记得开long long。

#include <bits/stdc++.h>
using namespace std;
#define N 100005
int n, m, tot = 0, head[N], ver[2 * N], Next[2 * N], l[N], r[N];
long long dp[N][2];//dp[i]是以i为根的子树的点权差值和
void add(int x, int y) {
	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
void dfs(int x, int pre) {
	for(int i = head[x]; i; i = Next[i]) {
		int y = ver[i];
		if(y == pre) continue;
		dfs(y, x);
		dp[x][0] += 1ll * max(dp[y][0] + abs(l[x] - l[y]), dp[y][1] + abs(l[x] - r[y]));
		dp[x][1] += 1ll * max(dp[y][0] + abs(r[x] - l[y]), dp[y][1] + abs(r[x] - r[y]));
	}
}
signed main() {
	int t;
	cin >> t;
	while(t--) {
		cin >> n;
		tot = 0;
		for(int i = 1; i <= n; i++) {
			head[i] = 0;
			dp[i][0] = dp[i][1] = 0;
			scanf("%d%d", &l[i], &r[i]);
		}
		for(int i = 1; i <= n - 1; i++) {
			int u, v;
			scanf("%d%d", &u, &v);
			add(u, v);
			add(v, u);
		}
		dfs(1, 0);
		cout << max(dp[1][0], dp[1][1]) << endl;
	}
	return 0;
}
posted @ 2021-05-25 23:53  脂环  阅读(316)  评论(0编辑  收藏  举报