CF1187E Tree Paiting(树形DP+换根)

CF1187E Tree Painting(树形DP+换根)

题意:

给出一棵树,开始所有的点都是白色的,你可以给树上的点染色。

一次染色,你可以选择任意一个和已经被染成黑色的点相邻的白点,将其染成黑色,并获得等同于这个点所在的白色连通块的点数的分数。询问最大分数。

题解:

先一遍DFS处理出每个点的子树节点数量,第二遍DFS不断更换根节点,维护当前所有子树节点数量和,取最大的就是答案。

//第一步选择一个白色顶点涂成黑色
//之后每步选择一个与黑色顶点相邻的白色顶点涂成黑色
//每涂一次的分数是这个点所在的白色连通块的点数
//询问最大分数
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
typedef long long ll;
int n;vector<int> g[maxn];
int size[maxn];
void dfs (int u,int f) {
    size[u]=1;
    for (int v:g[u]) {
        if (v==f) continue;
        dfs(v,u);
        size[u]+=size[v];
    }
}
ll sum,ans=0;
//换根
//从u转移到v
//size[u]变成n-size[v]
//size[v]变成n
void dfs1 (int u,int f) {
    for (int v:g[u]) {
        if (v==f) continue;
        int t1=size[u],t2=size[v];
        size[u]-=size[v];
        size[v]=n;
        sum+=size[u]-t1+size[v]-t2;
        ans=max(ans,sum);
        dfs1(v,u);
        sum-=size[u]-t1+size[v]-t2;
        size[u]=t1;size[v]=t2;
    }
} 
int main () {
    scanf("%d",&n);
    for (int i=1;i<n;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    dfs(1,0);
    for (int i=1;i<=n;i++) sum+=size[i];
    ans=sum;
    dfs1(1,0);
    printf("%lld\n",ans);
} 

 

posted @ 2020-09-23 16:03  zlc0405  阅读(102)  评论(0编辑  收藏  举报