2013 ACM区域赛长沙 I LIKE vs CANDLE(ZOJ3734) 很好的一道树形DP

题意:一棵有根树,每个节点都有一个value值和属性(zan或是 CANDLE)。你可以通过反转一些点的属性,反转一个点时候,它的整个子树都会被反转属性。有些点反转消耗代价为X,有些为Y。你的目标的是求zan和candle差的最大值。

思路:dp[i][0]代表zan比candle多的最大值,dp[i][1]代表zan比candle少的最大值。注意每次更新当前节点的状态,如果当祖先节点加上当前节点的反转状态为偶数当然val不变,否则变。此题信息比较多,注意化繁为简。转移方程见代码

 1 #include<cstdio>
 2 #include<stack>
 3 #include<vector>
 4 #include<map>
 5 #include<algorithm>
 6 #include<cstring>
 7 using namespace std;
 8 const int maxn=50010;
 9 vector<int>vec[maxn];
10 int dp[maxn][2];
11 int val[maxn],flip[maxn];
12 int n,X,Y;
13 int u,p;
14 int dfs(int t,int st) {
15     st+=flip[t];
16     if(st&1)
17         val[t]=-val[t];
18     dp[t][0]=val[t];
19     dp[t][1]=-val[t];
20     for(int i=0; i<vec[t].size(); i++) {
21         dfs(vec[t][i],st);
22         int v=vec[t][i];
23         dp[t][0]+=max(dp[v][0],dp[v][1]-(flip[v]?Y:X));
24         dp[t][1]+=max(dp[v][1],dp[v][0]-(flip[v]?Y:X));
25     }
26 }
27 int main() {
28 //    freopen("in.txt","r",stdin);
29     while(~scanf("%d%d%d",&n,&X,&Y)) {
30         for(int i=0; i<=n; i++)
31             vec[i].clear();
32         for(int i=1; i<=n; i++) {
33             scanf("%d%d%d%d",&val[i],&u,&flip[i],&p);
34             vec[u].push_back(i);
35             if(p) {
36                 val[i]=-val[i];
37             }
38         }
39         dfs(0,0);
40         if(dp[0][0]<0)
41             printf("HAHAHAOMG\n");
42         else
43             printf("%d\n",dp[0][0]);
44     }
45     return 0;
46 }
View Code

 

posted @ 2016-03-29 15:07  yyblues  阅读(291)  评论(0编辑  收藏  举报