https://ac.nowcoder.com/acm/contest/11168/C
思路:
算出来每个点为根的子树和然后暴力n^2更新都可以做。
但是要dp改进到on。
定义:
mx[u]:以u为总根的子树的最大值。
于是 每个点都可以求出来其u本身这棵大子树或者u里面某个儿子或者孙子的子树中综合的一个最大值。
那么此时跑dfs时,一个点就是代表其一边下方的最优子树状态。然后这样去枚举就可以达到全部状态的枚举了。
不同于换根,跑后序,把最左边的大子树内部更新好后更新最左边的大子树,然后更新中间的大子树的内部,再更新中间大子树和左边大子树的结合
(树形dp还是很容易想串的....
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL sum[maxn],mx[maxn],val[maxn];
vector<LL>g[maxn];
LL ans=-1e18;
void predfs(LL u,LL fa){
sum[u]=val[u];
for(LL i=0;i<g[u].size();i++){
LL v=g[u][i];
if(v==fa) continue;
predfs(v,u);
sum[u]+=sum[v];
///mx[u]=max(mx[u],sum[v]);///wa的原因:是从子树的每个max状态转移过来写成了sum[]
}
mx[u]=max(mx[u],sum[u]);
for(LL i=0;i<g[u].size();i++){
LL v=g[u][i];
if(v==fa) continue;
mx[u]=max(mx[u],mx[v]);
}
}
void dfs(LL u,LL fa){
LL mx1=-1e18;
LL mx2=-1e18;
for(LL i=0;i<g[u].size();i++){
LL v=g[u][i];
if(v==fa) continue;
if(mx1<mx[v]){
mx2=mx1;
mx1=mx[v];
}
else if(mx2<mx[v]){
mx2=mx[v];
}///得更完最大值再更新
dfs(v,u);
}
if(mx2!=-1e18) ans=max(ans,mx1+mx2);///后序遍历取dp状态的更新,不同于换根
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n;cin>>n;
for(LL i=1;i<=n;i++) cin>>val[i],mx[i]=-1e17;
for(LL i=1;i<n;i++){
LL u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
predfs(1,1);
dfs(1,1);
if(ans!=-1e18) cout<<ans<<"\n";
else cout<<"Error"<<"\n";
return 0;
}