Codeforces Round #627 (Div. 3) F - Maximum White Subtree (树形dp)

**F - Maximum White Subtree **

题目描述

You are given a tree consisting of n vertices. A tree is a connected undirected graph with n−1 edges. Each vertex v of this tree has a color assigned to it (av=1 if the vertex v is white and 0 if the vertex v is black).

You have to solve the following problem for each vertex v: what is the maximum difference between the number of white and the number of black vertices you can obtain if you choose some subtree of the given tree that contains the vertex v? The subtree of the tree is the connected subgraph of the given tree. More formally, if you choose the subtree that contains cntw white vertices and cntb black vertices, you have to maximize cntw−cntb.

Input

The first line of the input contains one integer n (2≤n≤2⋅10^5) — the number of vertices in the tree.

The second line of the input contains n integers a1,a2,…,an (0≤ai≤1), where ai is the color of the i-th vertex.

Each of the next n−1 lines describes an edge of the tree. Edge i is denoted by two integers ui and vi, the labels of vertices it connects (1≤ui,vi≤n,ui≠vi).

It is guaranteed that the given edges form a tree.

Output

Print n integers res1,res2,…,resn, where resi is the maximum possible difference between the number of white and black vertices in some subtree that contains the vertex i.

Examples

Input #1
9
0 1 1 1 0 0 0 0 1
1 2
1 3
3 4
3 5
2 6
4 7
6 8
5 9
Output #1
2 2 2 2 2 1 1 0 2

Input #2
4
0 0 1 0
1 2
1 3
1 4
Output #2
0 -1 1 -1

Note

The first example is shown below:


The black vertices have bold borders.

In the second example, the best subtree for vertices 2,3 and 4 are vertices 2,3 and 4 correspondingly. And the best subtree for the vertex 1 is the subtree consisting of vertices 1 and 3.

题意

有n个点n-1条边的树,问每个点所在连通块中白黑点数目最大差。

Solution

树形dp (换根).

令dp[u]为存在i节点的连通块的最大白黑节点差.对于父亲节点和儿子节点,只有儿子节点对父亲节点有贡献才向上传递,dp[u] += max(0,dp[v]);
做完一遍dp只能求出根节点的ans,因为贡献仅能向上传递,所以要求每个节点的ans,必须进行换根。

dfs2用来换根,当前根u的子节点v,记完u的答案,再把子节点v提上去做根,更新dp[u] = dp[u] - max(0,dp[v]),dp[v] = dp[v] + max(0,dp[u]),v变成根之后记录答案,依次类推下去,然后回溯(注意回溯顺序),把所有节点全部提为根一次,得到所有的ans值。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long ll;

const int INF = 0x3f3f3f3f;
const int SZ = 200000 + 200;

struct zt
{
	int v,nxt;
}node[SZ << 1];

int color[SZ],dp[SZ],fist[SZ],ans[SZ];
int n,temp; 

inline void build(int x,int y)
{
	node[ ++ temp].v = y;
	node[temp].nxt = fist[x];
	fist[x] = temp;
}

inline void dfs1(int u,int fa)
{
	if(color[u] == 1) dp[u] = 1;
	else dp[u] = -1;
	for(int i = fist[u];i != -1;i = node[i].nxt)
	{
		int v = node[i].v;
		if(v == fa) continue;
		dfs1(v,u);
		if(dp[v] > 0) dp[u] += dp[v]; 	
	}
}

inline void dfs2(int u,int fa)
{
	ans[u] = dp[u];
	for(int i = fist[u];i != -1;i = node[i].nxt)
	{
		int t = node[i].v;
		if(t == fa) continue;
		dp[u] -= max(0,dp[t]);
		dp[t] += max(0,dp[u]);
		dfs2(t,u);
		dp[t] -= max(0,dp[u]);
		dp[u] += max(0,dp[t]);
	}
} 

int main()
{
	int a,b;
	scanf("%d",&n);
	memset(fist,-1,sizeof(fist));
	for(int i = 1;i <= n;i ++ ) scanf("%d",&color[i]);
	for(int i = 1;i < n;i ++ )
	{
		scanf("%d%d",&a,&b);
		build(a,b);
		build(b,a);
	}
	dfs1(1,-1); 
	dfs2(1,-1);
	for(int i = 1;i <= n;i ++)
	printf("%d%c",ans[i],i == n?'\n':' ');
	return 0;
}

2020.3.15

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值