B. Zero Tree(思维+树形dp)

题意翻译

题目描述

一棵树是一个有n个节点与正好n-1条边的图;并且符合以下条件:对于任意两个节点之间有且只有一条简单路径。

我们定义树T的子树为一棵所有节点是树T节点的子集,所有边是T边的子集的树。

给定一颗有n个节点的树,假设它的节点被编号为1到n。每个节点有一个权值,v_ivi​表示编号为i的节点的权值。你需要进行一些操作,每次操作符合以下规定:

- 在给定的这棵树中选择一棵子树,并保证子树中含有节点1
- 把这棵子树中的所有节点加上或减去1

你需要计算至少需要多少次操作来让所有的节点的权值归零。 输入数据

第一行包含一个整数n,表示树中节点的数量

接下来的n-1行,一行两个整数u,v,表示u和v之间有一条边(u!=v)。

最后一行包含n个整数v_ivi​,用空格隔开,表示每个节点的权值 输出数据

一行一个整数,输出最小需要的操作次数。 输入样例

3
1 2
1 3
1 -1 1

输出样例

3

数据规模 对于30\%30%的数据,n\leq100,|vi|\leq1000n≤100,∣vi∣≤1000

对于50\%50%的数据,n\leq10^4n≤104

对于100\%100%的数据,n\leq10^5,|vi|\leq10^9n≤105,∣vi∣≤109

Translated by 首相大大

输入输出样例

输入 #1复制

3
1 2
1 3
1 -1 1

输出 #1复制

3

题意:每次选的时候一定要包含1,但是子树的大小不定,具体意思就是说选择了一个点,从这个点往上直到根节点1的经过的点都要同时加1/-1;

考虑树形dp,add[x]:x点增加的次数,del[x]:x点减少的次数。

对于父节点,遍历其儿子得出add[x]=max(add[x],add[v]),del[x]=max(del[x],del[v]);

原因在于,比如叶子节点a是7,叶子节点b是5,那么更新的时候,开始叶子节点a和叶子节点b同时更新-1,到了叶子节点b为0了,就单单更新叶子节点a。这样就是说其a和b的父亲节点更新最大的7就可以。那么-7和-5同理。

当叶子节点a是7,b是-5,那么两个点开始同时更新+1或者-1肯定不是最小,对b以及路上的+5,对a以及路上的-7,这样其a和b的父亲节点最终的更新值a[x]+=(add[x]-del[x]),也就是a[x]-=2,然后此时a和b叶子节点都为1,此时父亲节点重复同样的事情。树形dp即可。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define debug(a) cout<<#a<<"="<g[maxn];
void dfs(LL u,LL fa)
{
	for(LL i=0;i0){
		del[u]+=a[u];
	}	
	else{
		add[u]+=(-a[u]);
	}
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n;cin>>n;
  for(LL i=1;i>x>>y;
  	g[x].push_back(y);g[y].push_back(x);
  }
  for(LL i=1;i<=n;i++) cin>>a[i];
  dfs(1,0);
  cout<

 

你可能感兴趣的:(思维,树形dp)