时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
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.
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.
输入例子:
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有一定了解的话 肯定会将子链数加入状态。
可以得出最开始的一个状态定义
dp[i][j] 表示 以i点为根节点的子树,选出k条链的状态最大权值和。
但这样根本无法转移。
因为 当我们考虑从子节点状态 推出父亲节点状态时,如果要把当前父节点并入子链中时,我们定义的状态是显然不够用的。 因此要扩充状态数
开始考虑如何扩充。
考虑跟节点加入子节点的几种情况
1. 单独出来 成为一条只有一个点的链
2. 并入一条以子节点为端点的链
3. 链接两条以子节点为端点的链
第一种情况很好转移
但对于第二三种情况 用现有状态是无法转移的
这样 就可以定义出我们需要扩展的状态 link[i][j] 表示以i节点为跟的子树 有取j条链再加上一条以以根节点和叶子节点为端点链的最大取值。
就很好转移了。
PS 我总感觉这道题的数据有点水。
#include <bits/stdc++.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int MAX=4e5+10;
class Edge{
public:
int u,v,next;
};
Edge edge[MAX<<1];
int head[MAX];
int tot;
void add(int u,int v){
edge[tot].u=u;
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot;
tot++;
}
void init(){
memset(head,-1,sizeof head);
tot=0;
}
long long W[MAX];
long long link[MAX][4];
long long dp[MAX][4];
void dfs(int u,int pre){
long long per[4][4];
long long now[4][4];
long long cnt[4][4];
memset(per,0,sizeof per);
memset(now,0,sizeof now);
memset(cnt,0,sizeof cnt);
for(int i= head[u];i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==pre) continue;
dfs(v,u);
memset(cnt,0,sizeof cnt);
for(int j=0;j<4;j++){
cnt[j][0]=dp[v][j];
cnt[j][1]=link[v][j];
}
memset(now,0,sizeof now);
for(int j=0;j<4;j++){
for(int k=0;k+j<4;k++){
for(int s=0;s<=2;s++){
for(int t=0;s+t<=2;t++){
//cout<<"cnt:"<<k<<","<<t<<":"<<cnt[k][t]<<endl;
now[j+k][s+t]=max(now[j+k][s+t],per[j][s]+cnt[k][t]);
}
}
}
}
for(int j=0;j<4;j++){
for(int k=0;k<4;k++){
//cout<<per[j][k]<<" ,"<<now[j][k]<<endl;
per[j][k]=now[j][k];
}
}
}
// 转移dp数组
// 情况1 : 没有竖直链的情况
for(int i=0;i<4;i++){
dp[u][i]=per[i][0];
}
for(int i=0;i<4;i++){
dp[u][i]=max(dp[u][i],per[i-1][0]+W[u]);
}
// 2 : 竖直链合并
for(int i=1;i<4;i++){
for(int k=1;k<=2;k++)
dp[u][i]=max(dp[u][i],per[i-1][k]+W[u]);
}
// 转移link数组
for(int i=0;i<4;i++){
link[u][i]=per[i][1]+W[u];
}
}
int main(){
int n;
init();
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&W[i]);
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,-1);
cout<<dp[1][3]<<endl;
return 0;
}