https://ac.nowcoder.com/acm/contest/11168/C
アイデア:
各ポイントをルートとするサブツリーを計算すると、ブルートフォースn ^ 2の更新を実行できます。
しかし、dpをオンに改善するため。
定義:
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;
}