CF1324F Maximum White Subtree
Description
- 给定一棵 n n n 个节点无根树,节点 u u u 颜色为 a u a_u au,若 a u = 0 a_u=0 au=0 为黑点, a u = 1 a_u=1 au=1 为黑点。
- 对于每个节点 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 cnt_1 - cnt_2 cnt1−cnt2。
- 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105, 0 ≤ a u ≤ 1 0 \leq a_u \leq 1 0≤au≤1。
Solution
下午水了一道绿题。。。
我们设
r
t
=
1
rt=1
rt=1 ,这样考虑一个根节点的最优。
显然自下向上转移即可:
设
f
[
i
]
f[i]
f[i] 为以
i
i
i 为子树的最大值,则对
u
,
v
u,v
u,v 有:
i
f
(
f
[
v
]
>
=
0
)
f
[
u
]
+
=
f
[
v
]
;
if(f[v]>=0)\quad f[u]+=f[v];
if(f[v]>=0)f[u]+=f[v];
然后考虑由上至下转移:
无论怎样,u和fa可在同一个最优联通子图中或(断掉向上路径)和子树的一部分成图。
1.若
u
u
u 对
f
a
fa
fa 产生贡献(f[u]>=0),则:
a
n
s
[
u
]
=
m
i
n
(
a
n
s
[
v
]
,
f
[
u
]
)
;
ans[u]=min(ans[v], f[u]);
ans[u]=min(ans[v],f[u]);
2.若
u
u
u 对
f
a
fa
fa 无贡献(f[u]<0),则:
a
n
s
[
u
]
=
m
i
n
(
a
n
s
[
v
]
,
−
1
l
l
)
;
ans[u]=min(ans[v], -1ll);
ans[u]=min(ans[v],−1ll);
转移代码如下:
if(u==rt) ;//rt根节点的ans 先前第一遍dfs求出
else if(f[u]>=0) ans[u]=max(ans[fa], f[u]);
else ans[u]=max(ans[fa]-1, -1ll);
Code
ll f[maxn], ans[maxn];
void dfs(ll u, ll fa){
f[u]=a[u]?1:-1;
for(ll i = hd[u]; i ; i=e[i].nxt){
ll v=e[i].to;
if(v==fa) continue;
dfs(v, u);
if(f[v]>0) f[u]+=f[v];//产生(向上)贡献
}
}
void down(ll u, ll fa){
if(u==rt) ;//根节点
else if(f[u]>=0) ans[u]=max(f[u], ans[fa]);//f[u]>=0:有贡献
else ans[u]=max(ans[fa]-1, -1ll);//f[u]<0:无贡献
for(ll i = hd[u]; i ; i=e[i].nxt){
ll v=e[i].to;
if(v==fa) continue;
down(v, u);//向下转移
}
}
int main(){
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
//...初始化...
//...建边...
rt=1;
dfs(rt, 0);
ans[rt]=f[rt];//根节点答案
down(rt, 0);
//print:ans
return 0;
}