[树形dp]ICPC Nanjing 2021 H, Crystalfly解题思路

解题思路

我们注意到这题有个巧妙的地方 \(t_i\leq 3\),我们思考一下这个条件有什么用。

这就限制了我们在一个结点的选择,我们不可能走完两个很大的结点。如果我们站在当前的结点,我们只有几种可能。

  1. 对于当前的若干儿子,我们只能选择其中的一个权值
  2. 但是如果我们有一个 \(t_i=3\) 我们可以选择两个权值,但是要放弃另一个已经走过了的结点的两个儿子的权值。
    我们好像发现每个点的权值是跟儿子有关的。

我们定义 \(f_i\) 表示我儿子是可以正常选但是不包括自己的最大贡献,\(g_i\) 表示我儿子都选不了了也不包括自己的最大贡献,我们考虑到对于现在这个点的 \(f,g\) 分别转移。

\(f_u=\max\{f_{v1}+g_{v2}+a_{v1}+a_{v2}+\sum_{v\not=v1\&v\not=v2}f_v\},t_{v1}=3\)

我们尝试合并一些东西

\(f_u=\max\{a_{v1}+g_{v2}+a_{v2}+\sum_{v\not=v2}f_v\},t_{v1}=3\)

我们好像看出什么了,我们会选一个 \(t_{v}=3\)\(a\) 的最大值选择。那么 \(v2\) 是如何选择的呢。观察到如果一个点 \(v\) 被选择成了 \(v2\)。本来能有的贡献为 \(f_v\) 现在被迫之后的贡献为 \(g_v+a_v\)。中间的差值为 \(g_v+a_v-f_v\) 选择其中一个最大的就好了,但是我们要记住 \(v1\not= v2\)。但是我们不一定会优先选择 \(v1\) 也有可能优先选择 \(v2\) 我们两种情况都要考虑一下,这是一开始想到的,WA 了一发验证出来的。

或者我们可以不选择折返,这种情况下显得简单多了。

\(f_u=\max\{a_v+\sum f_v\}\)

显然那个单独的 \(v\) 我们选择 \(a_v\) 最大的即可。

我们如何转移 \(g\) 呢?如果是 \(g\),我们就不能正常的选择儿子了,那么没什么好纠结的。

\(g_u=\sum f_v\)

尝试一下把。

竟然自己 A 了这道题。

#include <bits/stdc++.h>
using namespace std;
template <typename T>inline void read(T& t){t=0; register char ch=getchar(); register int fflag=1;while(!('0'<=ch&&ch<='9')) {if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args> inline void read(T& t, Args&... args) {read(t);read(args...);}
const int N=1e5+10, inf=0x3f3f3f3f;

typedef long long ll;
int T,n,t[N];
ll a[N],f[N],g[N];
vector<int>G[N];

void dfs(int u,int fa){
    f[u]=g[u]=0;
    for(int v:G[u]){
        if(v==fa) continue;
        dfs(v,u);
        g[u]+=f[v];
    }
    // 不选择折返
    ll maxx=0;
    for(int v:G[u]) if(v!=fa) maxx=max(maxx,a[v]);
    f[u]=maxx+g[u];
    // 选择折返
    maxx=0;
    int maxh;
    for(int v:G[u]) if(v!=fa&&t[v]==3&&a[v]>maxx) maxx=a[v],maxh=v;
    ll minn=-inf*inf;
    for(int v:G[u]) if(v!=fa&&v!=maxh&&g[v]+a[v]-f[v]>minn) minn=g[v]+a[v]-f[v];
    f[u]=max(f[u],g[u]+maxx+minn);
    maxh=0; minn=-inf*inf;
    for(int v:G[u]) if(v!=fa&&g[v]+a[v]-f[v]>minn) minn=g[v]+a[v]-f[v],maxh=v;
    maxx=0;
    for(int v:G[u]) if(v!=fa&&v!=maxh&&t[v]==3&&a[v]>maxx) maxx=a[v];
    f[u]=max(f[u],g[u]+maxx+minn);
}

int main(){
    read(T);
    while(T--){
        read(n);
        for(int i=1;i<=n;++i) G[i].clear();
        for(int i=1;i<=n;++i) read(a[i]);
        for(int i=1;i<=n;++i) read(t[i]);
        for(int i=1;i<n;++i){
            int u,v;
            read(u,v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,-1);
        printf("%lld\n",f[1]+a[1]);
    }
    return 0;
}
/*
是谁挥霍的时光啊,是谁苦苦的奢望啊

这不是一个问题,也不需要你的回答

No answer. 
*/
posted @ 2022-08-27 20:32  Mercury_City  阅读(100)  评论(0编辑  收藏  举报