codeforces1485 E. Move and Swap(dp)

E. Move and Swap

Heltion
由于红色硬币向下一层走的时候只能走儿子,而蓝色无限制(对后续操作无影响),于是考虑下面表示

状态表示: f u f_u fu表示当前是红色硬币,向下一层走后的最大价值。
状态转移:
假设下一步走到儿子 v v v,并且不交换,也就是 v v v是红色硬币,存在转移 f u = f v + ∣ a v − a m ∣ f_u=f_v+|a_v-a_m| fu=fv+avam m m m表示与 v v v同层的那些节点

如果交换,那么 v v v就是蓝色硬币,需要找到一个与 v v v同层的节点 m m m(作为红色)存在转移 f u = f m + ∣ a v − a m ∣ f_u=f_m+|a_v-a_m| fu=fm+avam

去掉绝对值,预处理一些东西辅助转移即可( v → u v\to u vu)我为人人转移

#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;
}

写的时候状态定义不好,导致不容易转移,以后状态定义明确后在下手!

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/113799925