[HDOJ 4799][BNUOJ 34021] LIKE vs CANDLE [树形DP]

本文探讨了如何通过反转特定账户的立场来最大化获得的赞账户权值与减去踩账户权值之差,并在给定的数据范围内寻找最优策略。文章详细介绍了题目的背景、数据结构、状态转移方程以及解决思路,旨在帮助读者理解复杂题意并掌握解决此类问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

坑题...最开始题意理解错了...找了好长时间..和别人对拍数据才发现是题意理解错了..

已知在微博上的一条信息以及一些转发,转发一定是从原信息转发或者从某个转发转发,转发时会带一个自己的立场“赞”或“踩”。每个账户仅会转发一次,原账户不会转发。现在你可以反转某个账户的立场,反转立场后转自该账户的账户的立场也会被反转。反转一个账户的立场一次需要花费X。现在发现有一些账户是已经被别人反转过的,反转这些账户的立场需要的花费不是X而是Y。每个账户都有一个权值。求让你反转某些账户的立场后,所能够得到的"赞"账户权值和减去"踩"账户权值和再减去你的花费的最大值。

要注意题目里给出的立场时该账户的原始立场而不是被反转过的。别人反转某个账户的立场的时候,也是会将转发自该账户的账户的立场反转的...

数据范围:点的个数小于50000

因为每个账户不会转发两次,所以整个转发表构成了一棵树。对于每个点,记录两个值,dp1:不对其进行反转所能够得到的最高收益,dp2:对其反转所能够得到的最高收益(未记入当前点的反转花费)。状态转移方程见代码。


#include <cstdio>
#include <cstring>
inline int max(int a,int b) {
	return a>b?a:b;
}
struct Node {
	int fe,dp1,dp2,value,cost;
	int fs,nb;
	bool flag;
};
Node a[50010];
int p;
void befather(int son,int father) {
	a[son].nb=a[father].fs;
	a[father].fs=son;
}
void dfs(int i,bool notflip) {
	if (a[i].flag==true) notflip=!notflip;
	if (notflip) {
		a[i].dp1=a[i].value;
		a[i].dp2=-a[i].value;
	} else {
		a[i].dp2=a[i].value;
		a[i].dp1=-a[i].value;
	}
	for (int j=a[i].fs;j!=0;j=a[j].nb) {
		dfs(j,notflip);
		a[i].dp1+=max(a[j].dp1,a[j].dp2-a[j].cost);
		a[i].dp2+=max(a[j].dp2,a[j].dp1-a[j].cost);
	}
}
int main() {
	int n,x,y,i;
	while (scanf("%d%d%d",&n,&x,&y)!=EOF) {
		memset(a,0,sizeof(a));
		p=1;
		for (i=1;i<=n;i++) {
			int from,s,p;
			scanf("%d%d%d%d",&a[i].value,&from,&s,&p);
			befather(i,from);
			if (s) {
				a[i].cost=y;
				a[i].flag=true;
			} else a[i].cost=x;
			if (p) a[i].value=-a[i].value;
		}
		dfs(0,true);
		if (a[0].dp1>=0) printf("%d\n",a[0].dp1);
		else printf("HAHAHAOMG\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值