题解CF1324F Maximum White Subtree

Posted cjtcalc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解CF1324F Maximum White Subtree相关的知识,希望对你有一定的参考价值。

[ exttt{Description} ]

给定一棵 (n) 个点的树,每个点有一个颜色( "黑" 或 "白" )。

对于每个点 (x) ,求出所有包含点 (x) 的联通子图中,白点数减去黑点数的最大值是多少。
[ exttt{Solution} ]

  • 树形 dp 好题。
  • 首先我们随便找一个点定个根,就以 (1) 为根吧。
  • (f_x) 表示:在以 (x) 为根的子树内,所有包含点 (x) 的联通子图中,白点数减去黑点数的最大值。
  • 对于点 (u) 的每个儿子 (v) ,若 (f_v) 没有产生负贡献,则可以计入 (f_u) 中,再结合 (u) 点自身,不难得到转移:

[ f_u = egin{cases} sumlimits_{v in ext{son(u)}}max(f_v,0)-1 & col_x = exttt{black} \ sumlimits_{v in ext{son(u)}}max(f_v,0)+1 & col_u = exttt{white} end{cases} ]

  • 从下至上树形 dp 即可求出 (f)
  • 接下来就是换根 dp 了,设 (g_x) 表示:所有包含点 (x) 的联通子图中,白点数减去黑点数的最大值。
  • 首先可以确定的是 (g_{root}=f_{root})
  • 我们发现刨去以 (x) 为根的子树,剩下这部分比较难求答案。
  • 刨去以 (x) 为根的子树给我们启发,仔细思考便知 (max(g_{fa}-max(f_u,0),0)) 即为刨去以 (x) 为根的子树,剩下部分的答案,不难得到转移:

[ g_u = egin{cases} f_u & u= exttt{root} \ f_u +max(g_{fa}-max(f_u,0),0) & u eq exttt{root} end{cases} ]

  • 从上至下换根 dp 即可求出 (g)
  • (mathcal{O(n)})评测链接

[ exttt{Code} ]

#include<cstdio>
#include<algorithm>
#include<queue>

#define RI register int

using namespace std;

namespace IO
{
    static char buf[1<<20],*fs,*ft;
    inline char gc()
    {
        if(fs==ft)
        {
            ft=(fs=buf)+fread(buf,1,1<<20,stdin);
            if(fs==ft)return EOF;
        }
        return *fs++;
    }
    #define gc() getchar()
    inline int read()
    {
        int x=0,f=1;char s=gc();
        while(s<'0'||s>'9'){if(s=='-')f=-f;s=gc();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();}
        return x*f;
    }
}using IO::read;

const int N=200100,M=400100;

int n;

int a[N];

int tot,head[N],ver[M],Next[M];

void add(int u,int v)
{
    ver[++tot]=v;    Next[tot]=head[u];    head[u]=tot;
}

int f[N];

int g[N];

void calc(int u,int fu)
{
    if(a[u]==1)
        f[u]++;
    else
        f[u]--;

    for(RI i=head[u];i;i=Next[i])
    {
        int v=ver[i];

        if(v==fu)continue;

        calc(v,u);

        if(f[v]>0)
            f[u]+=f[v];
    }
}

bool vis[N];

void bfs()
{
    queue<int>q;

    q.push(1);
    g[1]=f[1];
    vis[1]=true;

    while(q.size())
    {
        int u=q.front();q.pop();

        for(RI i=head[u];i;i=Next[i])
        {
            int v=ver[i];

            if(vis[v])
                continue;

            g[v]=f[v]+max(0,g[u]-max(0,f[v]));

            vis[v]=true;
            q.push(v);
        }
    }
}

int main()
{
    n=read();

    for(RI i=1;i<=n;i++)
        a[i]=read();

    for(RI i=1;i<n;i++)
    {
        int u=read(),v=read();
        add(u,v),add(v,u);
    }

    calc(1,0);

    bfs();

    for(RI i=1;i<=n;i++)
        printf("%d ",g[i]);
    puts("");

    return 0;
}

[ exttt{Thanks} exttt{for} exttt{watching} ]

以上是关于题解CF1324F Maximum White Subtree的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 1324F Maximum White Subtree DFS

cf 627 F. Maximum White Subtree树形dp

CF1492C - Maximum width

CF1492C - Maximum width

[题解] [CF886E] Maximum Element

[树形dp][换根]Maximum White Subtree