1. 程式人生 > 其它 >題解 CF1187E 【Tree Painting】

題解 CF1187E 【Tree Painting】

大意

給一棵樹,初始時結點都為白色,然後你可以選一個點作為根節點,加上這個節點連通的白色節點數,然後把這個點染黑。下面再繼續選擇與黑節點相連的點,加上白色節點數,染黑。求最大的值。

思路

那麼我們很容易意識到,起關鍵作用的就是選擇了那個根節點。設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;

}