2019 年百度之星·程序设计大赛 - 复赛 Diversity (树形DP)

题目:https://vjudge.net/contest/325352#problem/A

题意:给你一棵树,每个点给一个区间,可以选区间里面任何一个数,然后问怎么安排得到最大边两点之间的差值和,求这个最大差值和

思路:首先可以想到每个点肯定是选择区间端点值,也就是说每个点实际上只有两个值可以选,但是我们安排当前值求出最大边差值不一定最优,这个时候我们可以设立一个数组dp[n][2],代表选当前点的L能得到的最大值和当前选R能得到的最大值,这样最后递归到根节点1就能求出最大值是多少

#include<bits/stdc++.h>
#define maxn 100005
#define mod 1000000007
using namespace std;
typedef long long ll;
struct sss{
    ll l,r;
}a[maxn];
int t,n; 
vector<int> mp[maxn];
ll dp[maxn][2];
void dfs(int x,int f){
    for(int i=0;i<mp[x].size();i++){
        int v=mp[x][i];
        if(v==f) continue;
        dfs(v,x);
        dp[x][0]+=max(abs(a[x].l-a[v].l)+dp[v][0],abs(a[x].l-a[v].r)+dp[v][1]);//所有子树的差值和
        dp[x][1]+=max(abs(a[x].r-a[v].l)+dp[v][0],abs(a[x].r-a[v].r)+dp[v][1]);
    } 
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            mp[i].clear();
        }
        memset(dp,0,sizeof(dp));
        int x,y;
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&x,&y);
            mp[x].push_back(y);
            mp[y].push_back(x);    
        }    
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].l,&a[i].r);
        }
        dfs(1,-1);
        printf("%lld\n",max(dp[1][0],dp[1][1])); 
    }
} 

猜你喜欢

转载自www.cnblogs.com/Lis-/p/11502379.html