E. Move and Swap
Heltion
由于红色硬币向下一层走的时候只能走儿子,而蓝色无限制(对后续操作无影响),于是考虑下面表示
状态表示:fuf_ufu表示当前是红色硬币,向下一层走后的最大价值。
状态转移:
假设下一步走到儿子vvv,并且不交换,也就是vvv是红色硬币,存在转移fu=fv+∣av−am∣f_u=f_v+|a_v-a_m|fu=fv+∣av−am∣,mmm表示与vvv同层的那些节点
如果交换,那么vvv就是蓝色硬币,需要找到一个与vvv同层的节点mmm(作为红色)存在转移fu=fm+∣av−am∣f_u=f_m+|a_v-a_m|fu=fm+∣av−am∣
去掉绝对值,预处理一些东西辅助转移即可(v→uv\to uv→u)我为人人转移
#define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
using ll=long long;
constexpr int N=200010;
constexpr ll INF=0x3f3f3f3f3f3f3f3f;
int h[N],e[2*N],ne[2*N],idx;
void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int d[N];
ll a[N];
vector<int> g[N];
ll f[N];
int fa[N],n;
void dfs_d(int u)
{d[u]=d[fa[u]]+1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(j==fa[u]) continue;fa[j]=u;dfs_d(j);}
}
void bfs(int S)
{for(int i=S;i>1;i--){// 不交换颜色u由儿子v转移ll vmin=INF,vmax=-INF;for(int v:g[i]) vmin=min(vmin,a[v]),vmax=max(vmax,a[v]);for(int v:g[i]){int u=fa[v];f[u]=max(f[u],max(a[v]-vmin,vmax-a[v])+f[v]);}// 交换颜色由同层节点转移ll p1=-INF,p2=-INF;for(int v:g[i]) p1=max(p1,f[v]+a[v]),p2=max(p2,f[v]-a[v]);for(int v:g[i]){int u=fa[v];f[u]=max(f[u],p1-a[v]);f[u]=max(f[u],p2+a[v]);} }
}
void init(int n)
{memset(h,-1,(n+1)*sizeof(int));idx=0;memset(d,0,(n+1)*sizeof(int));memset(fa,0,(n+1)*sizeof(int));memset(f,0,(n+1)*sizeof(ll));for(int i=0;i<=n;i++) g[i].clear();
}
int main()
{IO;int T=1;cin>>T;while(T--){cin>>n;init(n);for(int i=2;i<=n;i++){int v;cin>>v;add(v,i),add(i,v);}for(int i=2;i<=n;i++) cin>>a[i];dfs_d(1);for(int i=1;i<=n;i++) g[d[i]].push_back(i);bfs(*max_element(d+1,d+1+n));cout<<f[1]<<'\n';}return 0;
}
写的时候状态定义不好,导致不容易转移,以后状态定义明确后在下手!