題解 CF1187E 【Tree Painting】
阿新 • • 發佈:2021-06-24
大意
給一棵樹,初始時結點都為白色,然後你可以選一個點作為根節點,加上這個節點連通的白色節點數,然後把這個點染黑。下面再繼續選擇與黑節點相連的點,加上白色節點數,染黑。求最大的值。
思路
那麼我們很容易意識到,起關鍵作用的就是選擇了那個根節點。設dp[i]為以i為根節點的最大值。則,我們對於一個根節點,如點1,記sum[i]為i節點子樹的個數,則
$ dp[1]=sum[1]+sum[2]+...+sum[n] $
那麼轉移到下一個點,如2號點,有:
$ dp[2]=sum[1]+sum[3]+sum[4]+...+sum[n]+(sum[1]-sum[2]) $
很顯然,每次換根後,需要 $ -2*sum[to]+sum[1] $,2次搜尋即可
Code
AC程式碼
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll son[200005]; ll all,ans; vector<int>vec[200005]; void dfs1(int now,int fa,int dep){ all+=dep; son[now]=1; for(int i=0;i<vec[now].size();i++){ int to=vec[now][i]; if(to!=fa){ dfs1(to,now,dep+1); son[now]+=son[to]; } } } void dfs2(int now,int fa,ll val){ ans=max(ans,val); for(int i=0;i<vec[now].size();i++){ int to=vec[now][i]; if(to!=fa){ dfs2(to,now,val-2ll*son[to]+son[1]); } } } int main(){ all=0,ans=0; int n,a,b; scanf("%d",&n); for(int i=1;i<n;i++){ scanf("%d%d",&a,&b); vec[a].push_back(b); vec[b].push_back(a); } dfs1(1,1,1); dfs2(1,1,all); printf("%lld\n",ans); return 0; }