luogu p3478、p2986题解

luogo p3478

题目大意

给出一个无根树,求出一个节点,满足以该节点为根时,所有结点的深度之和最大。

题目思路

f 1 i f1_i f1i表示 i i i子树中所有结点的深度之和, f 2 i f2_i f2i表示 i i i子树外所有结点到 i i i的距离之和。

先以 1 1 1为根跑一遍 d f s dfs dfs,处理出 f 1 f1 f1数组,因为不是很难,所以具体实现参考代码。

void dfs1(int u,int fa)
{
    siz[u]=1;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v==fa)
            continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        f1[u]+=f1[v]+siz[v];
    }   
}

然后进行换根 d p dp dp

想象一下,当你将根从 u u u转向 v v v, f 2 v f2_v f2v f 2 u f2_u f2u多出了 v v v兄弟节点的贡献以及所有 v v v子树外的点到根的距离加 1 1 1

所以 f 2 v f2_v f2v就等于 f 2 u f2_u f2u加上 f 1 u f1_u f1u减去 f 1 v + s i z v f1_v+siz_v f1v+sizv,也就是 v v v兄弟节点的贡献,再加上 n − s i z v n-siz_v nsizv,这里 s i z v siz_v sizv表示 v v v子树的大小。

至此,核心部分就已经完成。

具体参考代码。

void dfs2(int u,int fa)
{
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v==fa)
            continue;
        f2[v]=f2[u]+f1[u]-f1[v]-siz[v]+(n-siz[v]);
        dfs2(v,u);
    }
}

答案就是 max ⁡ ( a n s , f 1 i + f 2 i ) , i ∈ [ 1 , n ] \max(ans,f1_i+f2_i),i\in[1,n] max(ans,f1i+f2i)i[1,n]

luogu p2986

就比 p 3478 p3478 p3478多了个边权,做法一模一样。

这里就不放代码了。

你可能感兴趣的:(题解,dp,算法)