Codeforces Round #168 (Div. 1)B 树形dp

//给一棵树,每次操作可以将包括顶点1的连通子集的所有点的节点加1或减1

//问最少几次操作使得这棵树的所有顶点的值都为0

//以1为根节点建树

//将加和减分开考虑,用up[u],down[u]表示以u为跟节点的子树中需要加的操作

//最大为up[u] ,需要减的操作最大为down[u]

//其余的加和减的操作则可以在处理这两个操作时一起覆盖

//在将u的子数全都处理完后u点的值由于在加了up[u]和减了down[u]后变为

//一个新的值,则对于这个新的值根据它的正负并入up[u]或down[u]

//直到更新到1节点结束

#include<cstdio>

#include<cstring>

#include<iostream>

using namespace std ;

const int maxn = 100010 ;

typedef __int64 ll;

ll dp[maxn] ;

int vis[maxn] ;

ll up[maxn] , down[maxn] ;

struct Edge

{

int  v;

int next ;

}edge[maxn*2] ;

int head[maxn] ;

int nedge ;

void addedge(int u , int v)

{

edge[nedge].v = v;

edge[nedge].next = head[u] ;

head[u] = nedge++;

edge[nedge].v = u ;

edge[nedge].next = head[v] ;

head[v] = nedge++ ;

}

void dfs(int u)

{

vis[u] = 1;

for(int i = head[u];i != -1 ;i = edge[i].next)

{

int v = edge[i].v;

if(vis[v]) continue ;

dfs(v) ;

up[u] = max(up[v] , up[u]) ;

down[u] = max(down[u] , down[v]) ;

}

ll t = dp[u] + up[u] - down[u] ;

if(t > 0) down[u] += t ;

else up[u] -= t;

}

void init()

{

memset(up , 0 , sizeof(up)) ;

memset(down , 0 , sizeof(down));

memset(vis , 0 ,sizeof(vis)) ;

memset(head , -1 , sizeof(head)) ;

nedge = 0 ;

}

int main()

{

//freopen("input.txt" ,"r" ,stdin) ;

int n ;

while(~scanf("%d" ,&n))

{

int u , v;

init() ;

for(int i = 1;i < n;i++)

{

scanf("%d%d" ,&u , &v) ;

addedge(u , v) ;

}

for(int i = 1;i <= n;i++)

scanf("%I64d" ,&dp[i]) ;

dfs(1) ;

printf("%I64d\n" ,up[1] + down[1]) ;

}

return 0;

}

时间: 2024-10-08 14:24:12

Codeforces Round #168 (Div. 1)B 树形dp的相关文章

Codeforces Round #135 (Div. 2) D 树形dp

//任选一个根节点,用dfs搜两遍,第一遍找以该节点为根节点 //每一个节点的子树中的相反的边 //第二遍dfs以同样的根节点搜索一遍,记录从根节点到该节点 //正向边和反向边dp[u] = dp[root] - sum_0 + sum_1 : #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int maxn = 200010 ; const int in

Codeforces Round #148 (Div. 1)C 树形dp

//枚举所有边,把该树分为两个树,分别求两颗数的最小的改变量 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int maxn = 3030 ; const int inf = 0x7fffffff ; int dp[maxn] ; struct Edge { int flag , v; int u ; int next ; }edge[2*maxn] ;

Codeforces Round #530 (Div. 2) E (树形dp+线段树)

链接: 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干需要花费bi时间,有两个玩家,玩家一可以移动到当前点的子节点也可以申请游戏结束返回根节点并吃沿途的饼干,玩家二可以删除当前点到儿子节点的一条边,走路和吃饼干都消耗时间,会给出一个总时间,在总时间内尽可能的多吃饼干,问最多能吃多少个? 思路: 由于是玩家一先手,那么最开始的最大边则不会被删除,但之后路途的最大边都会被玩家二删除,所以我们对于当前点我们需要求: 1.如果现在回头那么最多可以吃到多少饼干 2.向下

Codeforces Round #168 (Div. 1) B. Zero Tree 树形dp

题目链接: http://codeforces.com/problemset/problem/274/B 题意: 给出一棵树,每个点有权值,每次操作可以对一个联通子集中的点全部加1,或者全部减1,且每次操作必须包含点1,问最少通过多少次操作可以让整棵树每个点的权值变为0. 思路: http://blog.csdn.net/qq_24451605/article/details/48622953 定义状态up[u],down[u]代表点u被加操作的次数和点u被减操作的次数 因为必须包含点1,所以我

Codeforces Round #139 (Div. 2)C Barcode DP

#include<iostream> #include<cstdio> #include<cstring> using namespace std ; const int maxn = 1010; const int inf = 0x3f3f3f3f ; int dp[maxn][2] ; char str[maxn][maxn] ; int num[maxn]; int sum_b[maxn]; int sum_w[maxn]; int main() { // fre

Codeforces Round #276 (Div. 1)D.Kindergarten DP贪心

D. Kindergarten In a kindergarten, the children are being divided into groups. The teacher put the children in a line and associated each child with his or her integer charisma value. Each child should go to exactly one group. Each group should be a

Codeforces Round #271 (Div. 2) D.Flowers DP

D. Flowers We saw the little game Marmot made for Mole's lunch. Now it's Marmot's dinner time and, as we all know, Marmot eats flowers. At every dinner he eats some red and white flowers. Therefore a dinner can be represented as a sequence of several

Codeforces Round #105 (Div. 2) D 概率DP

题目 呃 琢磨了半天还是琢磨出来了,题意有些模糊哈,有w个白色物品,b个黑色物品,A,B轮着抽,A先开始,谁先抽到白色谁赢,若最终都没有抽到白色 则算B赢,抽出来的物品不会放回去,B抽完以后 物品还会有一个额外产生丢失,问A赢的概率为多少 依旧是以目标状态为边界,当前状态到目标状态所需要的概率为 方程 dp[i][j] 代表当前轮到A抽的时候,还有i个白色的j个黑色的A赢的概率为多少 则当前转移可能有四种 1:A抽到了白色的,那么直接赢了,接下来不需要继续,所以没有与其它状态方程有联系 2:A抽

Codeforces Round #387 (Div. 2) 747F(数位DP)

题目大意 给出整数k和t,需要产生一个满足以下要求的第k个十六进制数 即十六进制数每一位上的数出现的次数不超过t 首先我们先这样考虑,如果给你了0~f每个数字可以使用的次数num[i],如何求长度为L且满足要求的十六进制数有多少个 dp[i][l]表示使用了前i个数字,已经将L的空位填上了l个的数有多少个 转移方程 dp[i][l] = sigma(dp[i-1][l-j]*C[len-l+j[j]) 其中j是枚举填新的数的个数,C是组合数(选出j个空位填上新数) 有了这个dp后,现在的问题就变