码迷,mamicode.com
首页 > 其他好文 > 详细

题解【CF1324F Maximum White Subtree】

时间:2020-03-13 13:03:27      阅读:53      评论:0      收藏:0      [点我收藏+]

标签:+=   line   std   col   its   ref   表示   stat   最大   

\[ \texttt{Description} \]

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

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

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

\[ f_u = \begin{cases} \sum\limits_{v \in \text{son(u)}}\max(f_v,0)-1 & col_x = \texttt{black} \\ \sum\limits_{v \in \text{son(u)}}\max(f_v,0)+1 & col_u = \texttt{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 = \begin{cases} f_u & u=\texttt{root} \\ f_u +\max(g_{fa}-\max(f_u,0),0) & u \neq \texttt{root} \end{cases} \]

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

\[ \texttt{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;
}

\[ \texttt{Thanks} \ \texttt{for} \ \texttt{watching} \]

题解【CF1324F Maximum White Subtree】

标签:+=   line   std   col   its   ref   表示   stat   最大   

原文地址:https://www.cnblogs.com/cjtcalc/p/12485536.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!