Codeforces Round #527 F - Tree with Maximum Cost /// 樹形DP
阿新 • • 發佈:2018-12-20
題目大意:
給定一棵樹 每個點都有點權 每條邊的長度都為1
樹上一點到另一點的距離為最短路經過的邊的長度總和
樹上一點到另一點的花費為距離乘另一點的點權
選定一點出發 使得其他點到該點的花費總和是最大的
先dfs一遍 獲得 s[u] 為u點往下的點權總和(包括u點)
由其子節點v及其本身權值可得 s[u]=s[v]+w[u]
獲得 dp[u] 為u點出發往下的花費總和(u點出發的花費不需要包括u點)
由其子節點v的dp[v]及s[v]可得 dp[u]=dp[v]+s[v]
再深搜一遍樹形dp 獲得 dp[u] 為u點出發到其他所有點的花費總和
此時 fa=1 u=5
dp[fa]=dp[9]=1*(7+10+4)+2*(1+6+5+1)=(1+6+5)*2+(7+4+10)*1+1*2
dp[u]=dp[5]=1*(1+6+5+9)+2*(7+4)+3*1=(1+6+5)*1+9*1+(7+4)*2+1*3
發現由fa的結果得到u的結果需要 加上u往上的值 再減去u往下(包括u)的值
相當於 加上整棵樹的值sum 再減兩次u往下的值s[u] 即dp[u] = dp[fa] + sum - 2*s[u]
dp[fa]+sum-2*s[u] =(1+6+5)*2+(7+4+10)*1+1*2 + (1+6+5+7+4+10+9+1) -
=(1+6+5)*3+(7+4+10)*2+1*3+9 - 2*(10+1+6+5)
=(1+6+5)*1+(7+4)*2+1*3+9*1 = dp[u]
#include <bits/stdc++.h> #define LL long long #define INF 0x3f3f3f3f using namespace std; const int N=2e5+5; LL n, w[N]; LL ans, sum; LL s[N], dp[N]; // s[u]為u點往下的點的權值總和 vector <intView Code> E[N]; void dfs2(int u,int fa) { if(fa) dp[u]=dp[fa]+sum-2*s[u]; // 如果u存在父節點 由dp[fa]可得到dp[u] // 此時dp[u]為由u點出發去往其他所有點的總花費 for(int i=0;i<E[u].size();i++) { int v=E[u][i]; if(v==fa) continue; dfs2(v,u); } ans=max(ans,dp[u]); } void dfs1(int u,int fa) { s[u]=w[u]; for(int i=0;i<E[u].size();i++) { int v=E[u][i]; if(v==fa) continue; dfs1(v,u); s[u]+=s[v]; dp[u]=dp[u]+dp[v]+s[v]; // 此時dp[u]為由u點出發往下的總花費 } } int main() { while(~scanf("%I64d",&n)) { ans=sum=0LL; for(int i=1;i<=n;i++) { scanf("%I64d",&w[i]); sum+=w[i]; E[i].clear(); } for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); E[u].push_back(v); E[v].push_back(u); } memset(s,0,sizeof(s)); memset(dp,0,sizeof(dp)); dfs1(1,0); dfs2(1,0); printf("%I64d\n",ans); } return 0; }