题解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