题意:一棵有根树,每个节点都有一个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 "); 42 else 43 printf("%d ",dp[0][0]); 44 } 45 return 0; 46 }