题解 CF1187E 【Tree Painting】

GIFBMP

2020-03-24 08:42:34

Solution

树形DP好题! ### 正题 我们可以发现,确定第一个点后,后面选点的顺序就不影响权值了。 所以,我们设 $g_x$ 表示先选点 $x$ 时整棵树获得的权值。 我们发现,$g_x$ 直接算比较麻烦,所以,我们定义 $f_x$ 表示选了点 $x$ 后它的**子树**对它的贡献。 易得递推式: $$f_x=size_x+\sum_{i\in son_x}f_i$$ 于是我们得出: $$g_1=n+\sum_{\{i,1\}\in E}f_i$$ 然而,怎么算其它的 $g_i$ 呢?最暴力的思想是以每个点为根重新 $dfs$,然而,这样是 $\Theta (n^2)$ 的,通过不了本题。 所以我们要使用**换根DP**。 怎么换根呢? 来看下面的图: ![graph.png](https://i.loli.net/2020/03/24/msOAt6kfMxD9R2e.png) 易得: $$g_y=n+(n-size_y)+\sum_{i\in son_x|i\ne y}f_i+\sum_{i\in son_y}f_i$$ $$=n+(n-size_y)+\sum_{i\in son_x|i\ne y}f_i+f_y-size_y$$ $$=n+(n-size_y)+\sum_{i\in son_x}f_i-size_y$$ $$=g_x+n-2\times size_y$$ ### Code: ```cpp #include <cstdio> #include <vector> using namespace std ; typedef long long ll ; const int MAXN = 2e5 + 10 ; int n , size[MAXN] ; vector <int> G[MAXN] ; ll f[MAXN] , g[MAXN] , ans ; ll max (ll a , ll b) { return a > b ? a : b ; } void dfs1 (int x , int fa) { size[x] = 1 ; for (int i = 0 ; i < G[x].size () ; i++) { int v = G[x][i] ; if (v == fa) continue ; dfs1 (v , x) ; size[x] += size[v] ; f[x] += f[v] ; } f[x] += size[x] ; } void dfs2 (int x , int fa) { if (x != 1) { g[x] = g[fa] + n - size[x] * 2 ; ans = max (ans , g[x]) ; } for (int i = 0 ; i < G[x].size () ; i++) { int v = G[x][i] ; if (v == fa) continue ; dfs2 (v , x) ; } } int main () { scanf ("%d" , &n) ; for (int i = 1 ; i < n ; i++) { int u , v ; scanf ("%d %d" , &u , &v) ; G[u].push_back (v) ; G[v].push_back (u) ; } dfs1 (1 , 0) ; ans = g[1] = f[1] ; dfs2 (1 , 0) ; printf ("%lld" , ans) ; return 0 ; } ```