CF274B:Zero Tree
题目简述
给出一棵
n
个结点的带点权的树。每次可以选择包括根节点的一个连通块,令这个连通块中所有点的权值
数据范围
1≤|vi|≤109
思路
树形DP。
每次相当于是从当前点到根沿路打了加减标记。
f[i]
表示以
i
为根的子树需要加的值。
DP时候先加上孩子的贡献,再算出它往上的贡献。
转移看代码= =
代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
struct edge{
int s,t,next;
}e[200010];
int head[100010],cnt;
void addedge(int s,int t)
{
e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++;
e[cnt].s=t;e[cnt].t=s;e[cnt].next=head[t];head[t]=cnt++;
}
int n,u,v;
long long val[100010],f[100010],g[100010];
void dfs(int node,int lastfa)
{
f[node]=g[node]=0;
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa)
{
dfs(e[i].t,node);
f[node]=max(f[node],f[e[i].t]);
g[node]=min(g[node],g[e[i].t]);
}
val[node]+=f[node]+g[node];
if (val[node]>0)
g[node]-=val[node];
else
f[node]-=val[node];
}
int main()
{
scanf("%d",&n);
memset(head,0xff,sizeof(head));
for (int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
}
for (int i=1;i<=n;i++)
scanf("%I64d",&val[i]);
dfs(1,1);
printf("%I64d\n",abs(f[1])+abs(g[1]));
return 0;
}