牛客多校第二场 H travel(树形dp)

链接:https://www.nowcoder.com/acm/contest/140/H
来源:牛客网
 

题目描述

White Cloud has a tree with n nodes.The root is a node with number 1. Each node has a value.
White Rabbit wants to travel in the tree 3 times. In Each travel it will go through a path in the tree.
White Rabbit can't pass a node more than one time during the 3 travels. It wants to know the maximum sum value of all nodes it passes through.

输入描述:

The first line of input contains an integer n(3 <= n <= 400001)
In the next line there are n integers in range [0,1000000] denoting the value of each node.
For the next n-1 lines, each line contains two integers denoting the edge of this tree.

输出描述:

Print one integer denoting the answer.

示例1

输入

复制

13
10 10 10 10 10 1 10 10 10 1 10 10 10
1 2
2 3
3 4
4 5
2 6
6 7
7 8
7 9
6 10
10 11
11 12
11 13

输出

复制

110

题目大意:给定一棵树,每个点都有权值,要你求出树上三条不相交的链,使得链上的点权值和最大。

题目思路:考虑树形dp,对于一个结点 i 分为下面两种情况讨论

dp[i][j][0] 表示在 i 的子树中选择了 j 条链的最大权值和

dp[i][j][1] 表示在 i 的子树中选择了 j 条链,同时加一条包含 i 的竖直链的最大权值和(就是意味着有一条链是经过 i 连向根节点)

接下来对于每个结点 i

mx[j][0]表示在结点 i 的子树中选择 j 条链,同时子树内的结点与结点 i 形成链

mx[j][1]表示在结点 i 的子树中选择 j 条链,同时结点 i 形成竖直链链

mx[j][2]表示不选择子树中的任何一条链

在求mx[j][k]的过程中我们引入nw[j][k]和son[j][k]两个辅助数组来求值

nw[j][k]表示除去加上当前遍历到的子树的值之后每种情况所能得到的最优解

son[j][k]表示以当前子节点所形成的贡献(对于每个子节点,son的值是与子树的dp值相等的,只是为了方便计算再开的一个数组)

有了这些数组之后就可以进行状态转移,先对结点 i 的所有子节点的选链情况进行转移存在mx数组中,最后再更新dp值。

对于结点u有如下的状态转移方程

dp[u][i][0]=max(mx[i-1][j]+val[u])(i=1,2,3   j=0,1,2)

dp[u][i][1]=max(mx[i][j]+val[u]) (i=0,1,2,3  j=0,1)

具体操作看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
#define IOS ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
const int MX=4e5+7;

int n;
ll val[MX],dp[MX][4][2];
vector<int>E[MX];
void get_max(ll &x,ll y){x=max(x,y);}

void dfs(int u,int fa){
    ll mx[4][3],son[4][3],nw[4][3];
    memset(mx,0,sizeof(mx));

    for(auto v:E[u]){
        if(v==fa) continue;
        dfs(v,u);

        memset(son,0,sizeof(son));
        for(int i=0;i<=3;i++){
            son[i][0]=dp[v][i][0];
            son[i][1]=dp[v][i][1];
        }

        memset(nw,0,sizeof(nw));
        for(int i=0;i<=3;i++){
            for(int j=0;i+j<=3;j++){
                for(int k=0;k<=2;k++){
                    for(int l=0;l+k<=2;l++){
                        get_max(nw[i+j][k+l],mx[i][k]+son[j][l]);
                    }
                }
            }
        }
        memcpy(mx,nw,sizeof(nw));
    }

    for(int i=0;i<=3;i++) get_max(dp[u][i][0],mx[i][0]);
    for(int i=1;i<=3;i++){
        for(int j=0;j<=2;j++){
            get_max(dp[u][i][0],mx[i-1][j]+val[u]);
        }
    }
    for(int i=0;i<=3;i++){
        for(int j=0;j<2;j++){
            get_max(dp[u][i][1],mx[i][j]+val[u]);
        }
    }
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        E[u].pb(v);E[v].pb(u);
    }
    memset(dp,0,sizeof(dp));
    dfs(1,-1);
    printf("%lld\n",dp[1][3][0]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lee_w_j__/article/details/81160072
今日推荐