很好的题呢

n个节点的树,根为1,所有叶子的深度都是D,一开始根节点上有两个颜色分别微R,B的球,你执行下列操作D-1次:
1.R点跳到子树内
2.B点跳到下一层的任意节点
3.交换(R,B)[选做]
每次操作结束时,加上上abs(a[R所在点]-a[B所在点])

  • 思路:这样每层都是一个子问题,而且每次抉择都会影响下一个子问题,所以这个没办法贪心,于是考虑树上dp。
    dp[i]:表示R在i结点,第dep[i]~D层总最大价值和
    不交换:dp[u]=max(dp[v])+abs(a[u]a[u]) 其中vu的儿子。
    交换: dp[u]=max(dp[v]+abs(a[u]a[u])) 其中vu的儿子。
    若只有第一个式子就很好求,考虑第二个式子:
    vu是联系起来的,于是拆abs括号,改为max(dp[v]a[u]+a[u],dp[v]+a[u]a[u])
    然后我们就需要知道类似同层v'的mxson,然后按上面存一下。
    于是先dfs一遍,记录每层信息。
    再按层从下往上便历求解dp
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
ll dp[N],a[N],mx[N],mn0[N],mx0[N];
int D,nxt[N],head[N],fa[N],to[N],ecnt,dep[N],cnt;
vector<int> V[N];
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
void dfs1(int u) {
	dep[u]=dep[fa[u]]+1;
	cnt++;
	mx0[dep[u]]=max(mx0[dep[u]],a[u]);
	mn0[dep[u]]=min(mn0[dep[u]],a[u]);
	V[dep[u]].push_back(u);
	D=max(D,dep[u]);
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];
		if(v==fa[u])continue;
		fa[v]=u;
		dfs1(v);
	}
}
void solve() {
	for(int i=D;i>=1;i--) {
		ll mx1=-1e18,mx2=-1e18;
		for(int q=0;q<V[i].size();q++) {
			int u=V[i][q],w=max(abs(a[u]-mx0[dep[u]]),abs(a[u]-mn0[dep[u]]));
			if(i==D) {dp[u]=w;continue;}
			for(int j=head[u];j;j=nxt[j]) {
				int v=to[j];
				if(v==fa[u])continue;
				mx[u]=max(mx[u],dp[v]);
				dp[u]=max(dp[u],dp[v]+w);
			}
			mx1=max(mx1,mx[u]+a[u]);
			mx2=max(mx2,mx[u]-a[u]);
		}
		if(i!=D) {
			for(int q=0;q<V[i].size();q++) {
				int u=V[i][q];
				dp[u]=max(dp[u],max(mx1-a[u],a[u]+mx2));
//				printf("%d: %lld\n",u,dp[u]);
			}
		}
		V[i].clear();
	}
}
int main() {
	int T,n;
	scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		ecnt=0;
		for(int i=1;i<=n;i++) mn0[i]=1e9,dp[i]=head[i]=mx0[i]=mx[i]=0;
		for(int i=2;i<=n;i++) {
			int v;
			scanf("%d",&v);
			add_edge(i,v),add_edge(v,i);
		}
		for(int i=2;i<=n;i++) scanf("%lld",&a[i]);
		dfs1(1);
		solve();
		printf("%lld\n",dp[1]);
	}
	return 0;
}