CF1485E题解
题解思路:
设
我们再枚举一个
我们可以加入一些优化:
g(x) = dp_{fa_{x}} + a_{x} 那么我们就只需要记录
f(x),g(x) 的最大值就可以了,我们就在转移时直接用就可以了。状态转移变为:
$dp_{y} = \max (dp_{y}, - a_{y} + \max{g(x)})$。
时间复杂度就变成了:
AC CODE:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 200010;
int n;
ll dp[N];
vector <int> e[N] , d[N];
int fa[N] , deep[N] , ma[N] , mi[N] , a[N];
void dfs (int u , int pre) {
deep[u] = deep[pre] + 1;//深度,他的深度为他的父节点的深度加一
d[deep[u]].push_back (u);//每一层有那些值
ma[deep[u]] = max (ma[deep[u]] , a[u]);//每一层的最大值
mi[deep[u]] = min (mi[deep[u]] , a[u]);//每一层的最小值
for (auto v : e[u]) {
if (v == pre) continue;
fa[v] = u;//预处理fa数组
dfs (v , u);//递归他的儿子节点
}
}
void init () {//初始化
for (int i = 1; i <= n; ++ i) {
e[i].clear ();
d[i].clear ();
dp[i] = fa[i] = deep[i] = ma[i] = 0;
mi[i] = 2e9;
}
}
int main() {
memset (mi , 0x3f , sizeof (mi));
int T;
scanf ("%d" , &T);
while (T --) {
init ();
scanf ("%d" , &n);
for (int i = 2; i <= n; ++ i) {
int x;
scanf ("%d" , &x);
e[x].push_back (i);//连边
e[i].push_back (x);
}
for (int i = 2; i <= n; ++ i) scanf ("%d" , &a[i]);
dfs (1 , 1);//预处理
ll ans = 0;
for (int i = 2; i <= n; ++ i) {
ll val1 = 0 , val2 = -2e9;//初始化
for (auto x : d[i]) {//就是预处理f,g
val1 = max (val1 , dp[fa[x]] + a[x]);
val2 = max (val2 , dp[fa[x]] - a[x]);
}
for (auto x : d[i]) {
dp[x] = max (dp[x] , dp[fa[x]] + max (ma[i] - a[x] , a[x] - mi[i]));//第一个转移方程
dp[x] = max (dp[x] , max (val1 - a[x] , val2 + a[x]));//第二个
ans = max (ans , dp[x]);//求个最大值
}
}
printf ("%lld\n" , ans);//输出
}
return 0;
}
码字不易,求赞!