CF1324F题解

题目大意

给出一颗 n n n个节点的无根树,每个节点有一个颜色 a u a_u au,如果 a u = 0 a_u=0 au=0则为黑色,否则为白色。

对于每个节点 u u u,选出一个包含 u u u的联通子图,设子图中白点个数为 c n t 1 cnt_1 cnt1,黑点个数为 c n t 2 cnt_2 cnt2,输出 c n t 1 − c n t 2 cnt1-cnt_2 cnt1cnt2的最大值。

1 ≤ n ≤ 2 ∗ 1 0 5 , 0 ≤ a u ≤ 1 1 \leq n \leq 2*10^5,0 \leq a_u \leq 1 1n2105,0au1

题目思路

先以 1 1 1为根,预处理出每个点的子树中 c n t 1 − c n t 2 cnt_1-cnt_2 cnt1cnt2的最大值。

然后进行换根 d p dp dp

当你把根从 u u u转移到 v v v时, f 2 v = max ⁡ ( f 2 u + f 1 u − m a x ( f 1 v , 0 ) , 0 ) f2_v= \max(f2_u+f1_u-max(f1_v,0),0) f2v=max(f2u+f1umax(f1v,0),0)

f 1 f1 f1就是上面预处理的数组, f 2 f_2 f2就是每个点子树外 c n t 1 − c n t 2 cnt_1-cnt_2 cnt1cnt2的最大值。

因为只有根是必选的,所以其他值需要跟 0 0 0 m a x max max

具体实现参考代码。

#include
using namespace std;
const int N=200000+10;
int n,a[N],f1[N],f2[N];
int head[N<<1],nxt[N<<1],to[N<<1],tot=0;
void add(int u,int v)
{
    to[++tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}
int read()
{
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }   
    while(ch>='0'&&ch<='9')
        s=s*10+(ch-'0'),ch=getchar();
    return s*w;
}
void dfs1(int u,int fa)
{
    if(a[u])
        f1[u]=1;
    else    
        f1[u]=-1;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v==fa)
            continue;
        dfs1(v,u);
        f1[u]+=max(f1[v],0);
    }
}
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]=max(f2[u]+f1[u]-max(f1[v],0),0);
        dfs2(v,u);
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
        a[i]=read();
    for(int i=1;i<=n-1;++i)
    {
        int u=read(),v=read();
        add(u,v);
        add(v,u);
    }   
    dfs1(1,1);
    dfs2(1,1);
    for(int i=1;i<=n;++i)
        printf("%d ",f1[i]+f2[i]);
    return 0;
}

你可能感兴趣的:(dp,动态规划,算法)