CF1187E Tree Painting
作者:互联网
分析
首先,我们贪心的想,当第一个点确定后,我们所求的最大值就是,依次选择子节点
这样,我们可以用树形DP求出以1
为根的树,所能得到的最大权值。
递推公式为
\[f[i] = sz[i] + \sum_{j = son_1}^{son_m}f[j] \]则,我们可以轻松得到
\[f[1] = n + \sum_{j = son_1}^{son_m}f[j] \]但是我们需要求出以每个点为根节点能得到的最大值的最大值
当然不难想到,用换根DP啦。
推换根DP的公式
子节点son
分为两部分,前边为原本son
下边的,后边的是,将父节点变为子节点后的贡献。
我们开始对式子进行拼接变形。
\[g[son] = n + \sum_{j = son_1}^{son_s}f[j] + sz[son] - sz[son] + g[f] - sz[son] - f[son] \]其中分别加sz[son]
原因是为了是把那一个Σ处理一下。
式子最后变为
\[g[son] = n + f[son] + sz[son] + g[f] - 2*sz[son] - f[son] \]\[g[son] = n + sz[son] + g[f] - 2*sz[son] \]好嘞,直接看代码。
Ac_code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int h[N],ne[N<<1],e[N<<1],idx;
LL f[N],g[N],sz[N];
int n;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs1(int u,int fa)
{
sz[u] = 1;
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(j==fa) continue;
dfs1(j,u);
sz[u] += sz[j];
f[u] += f[j];
}
f[u] += sz[u];
}
void dfs2(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(j==fa) continue;
g[j] = g[u] + n - 2 * sz[j];
dfs2(j,u);
}
}
int main()
{
scanf("%d",&n);
memset(h,-1,sizeof h);
for(int i=0;i<n-1;i++)
{
int u,v;scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1,-1);
g[1] = f[1];
dfs2(1,-1);
LL ans = 0;
for(int i=1;i<=n;i++) ans = max(ans,g[i]);
printf("%lld\n",ans);
return 0;
}
标签:sz,sum,Tree,son,最大值,CF1187E,Painting,节点,DP 来源: https://www.cnblogs.com/aitejiu/p/16267727.html