2019百度之星复赛第一题题解(hdoj6725)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6725
题目:
Diversity
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 13 Accepted Submission(s): 10

Problem Description
给你一棵n个点的树,对于节点i,你要给它标上一个[li,ri]之间的数,要求所有边两端节点上标的数字的差的绝对值的总和最大。

Input
第一行一个整数T(1≤T≤5)表示数据组数。对于每组数据格式如下。

第一行一个正整数 n(2≤n≤105)。

接下来n−1行,每行两个正整数 u,v(1≤u,v≤n),表示一条边。

接下来n行,第i行两个正整数li,ri(1≤li≤ri≤109)。

Output
对于每组数据,一个整数表示答案。

Sample Input

1
5
1 2
2 3
3 4
4 5
1 5
2 7
7 9
5 8
3 4

Sample Output

16

Source
2019 年百度之星·程序设计大赛 - 复赛


思路:比赛的时候发现很多人能a掉这个,就盲猜了一个答案一定是取端点值时找到的,而这题显然是裸的树形dp,结合猜想写了一发就过了。
赛后听一队的人说单峰函数所以一定在端点什么的,没怎么理解QAQ。

AC代码:

#include
using namespace std;
typedef long long ll;
int t;
int n;
const int maxn=1e5+50;
vector<int> edge[maxn];
ll dp[maxn][2];
ll l[maxn];
ll r[maxn];
void dfs(int x)
{
	for(int i=0;i<edge[x].size();i++)
	{
		int y=edge[x][i];
		dfs(y);
		dp[x][0]+=max(dp[y][0]+abs(l[x]-l[y]),dp[y][1]+abs(l[x]-r[y]));
		dp[x][1]+=max(dp[y][0]+abs(r[x]-l[y]),dp[y][1]+abs(r[x]-r[y]));
	}
	return;
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			edge[i].clear();
			dp[i][0]=dp[i][1]=0;
		}
		for(int i=1;i<=n-1;i++)
		{
			int a,b;
			cin>>a>>b;
			edge[a].push_back(b);
		 } 
		for(int i=1;i<=n;i++)
		{
			cin>>l[i]>>r[i];
		}
		dp[0][0]=dp[0][1]=0;
		dfs(1);
		ll fin=0;
		for(int i=1;i<=n;i++)
		{
			fin=max(fin,dp[i][0]);
			fin=max(fin,dp[i][1]);
		}
		cout<<fin<<endl;
	}
	return 0;
 } 

你可能感兴趣的:(动态规划)