H. Crystalfly

H. Crystalfly
思路:
f [ u ] f[u] f[u] 表示以 u u u 为根的子树所能获得的最大值
g [ u ] g[u] g[u] 表示走到 u u u 然后立即返回能获得的值

假设 u u u 的子节点为 j
g [ u ] + = f [ j ] − a [ j ] g[u] += f[j] - a[j] g[u]+=f[j]a[j] 拿不到 u u u 的所有直接子节点 j j j
f [ u ] f[u] f[u] 的更新:
首先 如果 u u u 没有子节点则 f [ u ] = g [ u ] f[u] = g[u] f[u]=g[u], 如果叶子节点不是,则为 f [ u ] = g [ u ] + a [ j ] f[u] = g[u] + a[j] f[u]=g[u]+a[j]
然后 如果 t [ j ] = = 3 t[j] == 3 t[j]==3, 那么可以先去采一下 u u u 的其他直接子节点, 然后再回来拿采 j j j
假设这里去拿了点 z z z
z z z 对最后答案的贡献会变为为 g[z], 又因为 g[u] 中已经包含了一次 f [ z ] − a [ z ] f[z] - a[z] f[z]a[z], 所以需要减掉重复部分
为了求对最终 f [ u ] f[u] f[u] 的最大贡献,就需要求一下 g [ z ] − ( f [ z ] − a [ z ] ) g[z] - (f[z] - a[z]) g[z](f[z]a[z]) 的最大值与次大值 用于更新最后的 f [ u ] f[u] f[u]
代码:

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
int n;
const int N = 1e5 + 10, M = N * 2;
int e[M], ne[M], h[N], idx;
ll t[N], f[N], g[N], a[N];

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int fa) {
    g[u] = a[u];
    ll maxn1 = 0, maxn2 = 0;
    for(int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        dfs(j, u);

        g[u] += f[j] - a[j]; // 拿 u 但是不拿 u 的直接子节点
        ll temp = g[j] - (f[j] - a[j]);
        if(maxn1 < temp) {
            maxn2 = maxn1;
            maxn1 = temp;
        } else if(maxn2 < temp) maxn2 = temp;
    }
    f[u] = g[u]; //删掉后叶子节点无法更新
    for(int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        f[u] = max(f[u], g[u] + a[j]);
        if(t[j] == 3) {
            if(g[j] - f[j] + a[j] == maxn1) f[u] = max(f[u], g[u] + a[j] + maxn2);
            else f[u] = max(f[u], g[u] + a[j] + maxn1); 
        }
    }
}

void solve() {
    cin >> n;
    memset(h, -1, sizeof h);
    idx = 0;
    for(int i = 1; i <= n; i ++) cin >> a[i], f[i] = g[i] = 0;
    for(int i = 1; i <= n; i ++) cin >> t[i];
    for(int i = 1; i < n; i ++) {
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);
    }

    dfs(1, -1);
    cout << f[1] << '\n';
} 

signed main() {
   ios::sync_with_stdio(false); 
   cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
   freopen("D:/Cpp/program/Test.in", "r", stdin);
   freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
    int t;
    cin >> t;
    while(t --) solve();
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值