Educational Codeforces Round 67 E.Tree Painting (树形dp)

题目链接 

题意:给你一棵无根树,每次你可以选择一个点从白点变成黑点(除第一个点外别的点都要和黑点相邻),变成黑点后可以获得一个权值(白点组成连通块的大小) 问怎么使权值最大

思路:首先,一但根确定了,整棵树的权值就只需要模拟即可,所以思路就转换为求哪一个点为根的权值最大。

这题需要用到一个二次扫描换根的思想,我们可以先从任意一个点去进行树形dp 并且得到从这个点开始去逐渐更新他的儿子节点

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define ll long long int
using namespace std;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
int moth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int dir[4][2]={1,0 ,0,1 ,-1,0 ,0,-1};
int dirs[8][2]={1,0 ,0,1 ,-1,0 ,0,-1, -1,-1 ,-1,1 ,1,-1 ,1,1};
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
int n;
vector<int> G[200007];
ll dp[200007]; //表示i节点以下的所有贡献
ll f[200007];  //以i为根的权值
ll nump[200007]; //儿子节点数(包含自己)
void dfs(int u,int fa){
    nump[u]=1;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==fa) continue;
        dfs(v,u);
        nump[u]+=nump[v];
    }
}
void dfss(int u,int fa){
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==fa) continue;
        dfss(v,u);
        dp[u]+=dp[v];
    }
    dp[u]+=nump[u];
}
void change(int u,int fa){
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==fa) continue;
        f[v]=f[u]-nump[v]-dp[v]+n-nump[v]+dp[v]; //核心代码
        change(v,u);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v; cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);  
    dfss(1,0);
    f[1]=dp[1];
    change(1,0);
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,f[i]);
    }
    cout<<ans<<"\n";
    return 0;
}

 

posted @ 2019-07-03 13:42  WAKBGAN  阅读(273)  评论(0编辑  收藏  举报