HDU 4799 树形DP

题意

微博投票,有两种投票选择方式,一种是选择LIKE,另一种是选择CANDLE。允许进行一些翻转操作,有一些点是已经被别人翻转过的,对于这些点我们翻转需要消耗Y的票数,对于其他的点我们翻转需要消耗X的票数。问我们最多可以得到LIKE-CANDLE票数最大值是多少。

题解

题目很难读,有很多坑。比如说给的投票状态是最初的状态,也就是别人还没有反转的状态,因此如果别人翻转了的话,我们还需要在DFS的过程中进行反转。
另外的话,对于反转消耗的计算,我们可以在父状态DP的时候进行计算。(因为是否翻转不仅仅由当前状态决定,还由父状态决定,如果父状态已经反转了,那么子状态默认就是反转的,因此需要在父状态时候判定消耗)
至于其他的也就没什么了,由于数据范围不大,因此直接树形DP就可以了。

代码

#include<bits/stdc++.h>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define W(t) while(t)
#define MEM(a,b) memset(a,b,sizeof(a))
#define MAXN 100010
#define INF 0x3f3f3f3f
using namespace std;
int X[2];

vector<int> son[50010];
int p[50010],s[50010],val[50010];
int dp[50010][2];
void dfs(int u,int d){
    d^=s[u];
//    cout<<u<<" "<<d<<endl;
    if(p[u]) val[u]=-val[u];
    if(d) val[u]=-val[u];
    dp[u][0]=val[u];
    dp[u][1]=-val[u];
//    cout<<u<<" "<<dp[u][0]<<" "<<dp[u][1]<<endl;
    for(int v:son[u]){
        dfs(v,d);
        dp[u][0]+=max(dp[v][0],dp[v][1]-X[s[v]]);
        dp[u][1]+=max(dp[v][1],dp[v][0]-X[s[v]]);
    }
}

int main(){
    int n;
    W(~scanf("%d%d%d",&n,&X[0],&X[1])){
        MEM(dp,0);
        MEM(son,0);
        int f;
        UP(i,1,n+1){
            scanf("%d%d%d%d",&val[i],&f,&s[i],&p[i]);
            son[f].push_back(i);
        }
        dfs(0,0);
        int ans=dp[0][0];
        if(ans>=0){
            printf("%d\n",ans);
        }else{
            puts("HAHAHAOMG");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zhenlingcn/article/details/78163237