1. 程式人生 > >[codeforces274b]Zero Tree(樹形dp)

[codeforces274b]Zero Tree(樹形dp)

自底向上 else get oid eof 樹形 char inline lib

題意:給出一棵樹,每個點有權值,每次操作可以對一個聯通子集中的點全部加1,或者全部減1,且每次操作必須包含點1,問最少通過多少次操作可以讓整棵樹每個點的權值變為0.

解題關鍵:自底向上dp,記錄up,down兩個數組 代表u被加的次數和減的次數,以1為根,則

$up[u] = \max (up[v])$

$down[u] = \max (down[v])$

而子樹確定,該節點改變的次數也就確定了。從而推出該點的up和down的影響,至於為什麽取max,因為左右子樹可以互相影響,只要包含根節點即可。

 1 #include<cstdio>
 2 #include<cstring>
 3
#include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 #include<iostream> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=1e6+3; 10 const int inf=0x3f3f3f3f; 11 int head[maxn],tot,n,m,sum; 12 ll cnt[maxn]; 13 ll up[maxn],down[maxn]; 14 struct
edge{ 15 int to; 16 int nxt; 17 int w; 18 }e[maxn<<2]; 19 void add_edge(int u,int v){ 20 e[tot].to=v; 21 e[tot].nxt=head[u]; 22 head[u]=tot++; 23 } 24 25 void dfs1(int u,int fa){ 26 for(int i=head[u];i!=-1;i=e[i].nxt){ 27 int v=e[i].to; 28 if
(v==fa) continue; 29 dfs1(v,u); 30 up[u]=max(up[u],up[v]); 31 down[u]=max(down[u],down[v]); 32 } 33 cnt[u]+=up[u]-down[u]; 34 if(cnt[u]>0) down[u]+=cnt[u]; 35 else up[u]-=cnt[u]; 36 } 37 inline int read(){ 38 char k=0;char ls;ls=getchar();for(;ls<0||ls>9;k=ls,ls=getchar()); 39 int x=0;for(;ls>=0&&ls<=9;ls=getchar())x=(x<<3)+(x<<1)+ls-0; 40 if(k==-)x=0-x;return x; 41 } 42 43 int main(){ 44 int k=0; 45 while(scanf("%d",&n)!=EOF){ 46 memset(head,-1,sizeof head); 47 tot=0; 48 int a,b; 49 for(int i=0;i<n-1;i++){ 50 a=read(); 51 b=read(); 52 add_edge(a,b); 53 add_edge(b,a); 54 } 55 for(int i=1;i<=n;i++) scanf("%lld",&cnt[i]); 56 dfs1(1,-1); 57 printf("%lld\n",up[1]+down[1]); 58 } 59 return 0; 60 }

[codeforces274b]Zero Tree(樹形dp)