[TOPCODER14676]OwaskiAndTree

Posted by Dispwnl on October 16, 2018

题目

题目大意

给出一棵有根树,从根出发,走过一些节点

每个节点有一个得分,可以重复经过节点,但是只有第一次经过会改变当前得分

如果当前得分为负,会马上变成$0$

求最大得分

Examples

0)

{0, 1, 2, 3, 4, 5, 6, 7, 8}
{1, 1, -1, -1, -1, -1, 1, 1, 1, 1}

Returns:

4

1)

{0, 0, 1, 2}
{2, 3, 4, -1, -1}

Returns:

9

2)

{0, 0, 1, 1, 2, 2, 5, 5}
{1, 2, -3, -7, 3, 2, 7, -1, 3}

Returns:

17

3)

{0, 1, 1, 1, 0, 3, 1, 3, 4, 4, 3, 6, 8, 0, 12, 12, 11, 7, 7}
{-154011, 249645, 387572, 292156, -798388, 560085, -261135, -812756, 191481, -165204, 81513, -448791, 608073, 354614, -455750, 325999, 227225, -696501, 904692, -297238}

Returns:

3672275

4)

{}
{-1}

Returns:

0

题解

$dp$题全都没思路完蛋了qaq

因为可以重复走并且每个点只能拿一次,要是忽略得分为负就变为$0$的条件就是要找包含根的树上最大权连通子图,即$f_i$表示选$val_i$的子树最大权值,$f_i=max(0,val_i+\sum_{j\in son_i}max(0,f_j))$

考虑变成$0$的情况,如果到某个节点权值变为$0$,可以看成前面遍历的节点都没有选

所以用$g_i$表示可以不选$val_i$的子树最大权值,则$g_i=max(f_i,\sum_{j\in son}g_j)$

答案就是$g_0$了

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<vector>
# include<algorithm>
using namespace std;
const int MAX=1e3+5;
struct p{
	int x,y;
}c[MAX];
int n,num;
int h[MAX],val[MAX],f[2][MAX];
void add(int x,int y)
{
	c[++num]=(p){h[x],y},h[x]=num;
}
void dfs(int x=0)
{
	f[0][x]=val[x];
	for(int i=h[x];i;i=c[i].x)
	  dfs(c[i].y),f[0][x]+=max(f[0][c[i].y],0),f[1][x]+=f[1][c[i].y];
	f[0][x]=max(f[0][x],0),f[1][x]=max(f[1][x],f[0][x]);
}
class OwaskiAndTree{
	public:
		int maximalScore(vector<int> A,vector<int> B)
		{
			int n=B.size();
			for(int i=1;i<n;++i)
			  add(A[i-1],i);
			for(int i=0;i<n;++i)
			  val[i]=B[i];
			return dfs(),f[1][0];
		}
};