【树DP】2021ICPC南京 H

news/2024/7/23 17:43:59 标签: 算法

Problem - H - Codeforces
题意:

思路:

这题应该算是铜牌题

铜牌题 = 简单算法 + 基础思维

简单复盘一下思路

首先,我们发现有个很特殊的条件: ti <= 3

然后看一下样例:

注意到,对于一个结点 u ,如果它的所有子节点中没有 tv = 3的,那么就肯定是沿着一棵子树走到底,然后去走剩下的子树

如果所有子节点中有 tv = 3的,那么可以先走到某个子节点,然后再走到这个 tv = 3的结点

注意到了子问题,那么很自然地去考虑树DP

注意到子问题可以分类成不算结点u 和 算结点u, 因此可以这样设计状态

设 dp[u] 为没有走过结点 u的这棵子树的贡献

然后考虑转移

因为 ti <= 3, 考虑在转移的时候暴力分讨

因为怎么转移和这些子节点中是否存在 tv = 3的结点有关,那么考虑先去把这些结点遍历一遍,看看是否存在,然后去转移

如果存在,那么就是先走到某个结点,再走到这个tv = 3的结点

考虑枚举这个“某个结点”,注意到tv = 3的结点可能会有多个,我们贪心地保留av最大的那个,这个可以考虑用multiset维护

为了计算贡献,我们设sum[u]表示所有子节点的 dp[v] 之和

此时的贡献为:

dp[u] = max{sum[u] - dp[v] + sum[v] + a[v] + *rbegin()}

然后考虑不存在tv = 3的结点,那么就是一次性走到底,再去遍历其他结点,此时贡献为 sum[u] + mx,其中 mx 为所有子节点中最大的 a[v]

为了防止出问题,我们在原来的multiset中先插入 -Inf

Code:

#include <bits/stdc++.h>

#define int long long

using i64 = long long;

constexpr int N = 1e5 + 10;
constexpr int M = 1e5 + 10;
constexpr int P = 2e2 + 10;
constexpr i64 Inf = 1e18;
constexpr int mod = 1e9 + 7;
constexpr double eps = 1e-6;

std::vector<int> adj[N];

int n;
int a[N], t[N];
int dp[N], sum[N];

void dfs(int u, int fa) {
    std::multiset<int> S;
    int mx = 0;
    for (auto v : adj[u]) {
        if (v == fa) continue;
        dfs(v, u);
        sum[u] += dp[v];
        mx = std::max(mx, a[v]);
        if (t[v] == 3) S.insert(a[v]);
    }

    dp[u] = sum[u] + mx;
    S.insert(-0x3f3f3f3f);

    for (auto v : adj[u]) {
        if (v == fa) continue;
        if (t[v] == 3) S.erase(S.find(a[v]));
        dp[u] = std::max(dp[u], sum[u] - dp[v] + sum[v] + a[v] + (*S.rbegin()));
        if (t[v] == 3) S.insert(a[v]);
    }
}
void solve() {
    std::cin >> n;
    for (int i = 1; i <= n; i ++) {
        sum[i] = dp[i] = 0;
        adj[i].clear();
    }
    for (int i = 1; i <= n; i ++) {
        std::cin >> a[i];
    }
    for (int i = 1; i <= n; i ++) {
        std::cin >> t[i];
    }

    for (int i = 1; i <= n - 1; i ++) {
        int u, v;
        std::cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    dfs(1, -1);

    std::cout << dp[1] + a[1] << "\n";
}
signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t = 1;
    std::cin >> t;

    while (t--) {
        solve();
    }
    
    return 0;
}


http://www.niftyadmin.cn/n/4986338.html

相关文章

vr智慧党建主题展厅赋予企业数字化内涵

现如今&#xff0c;VR全景技术的发展让我们动动手指就能在线上参观博物馆、纪念馆&#xff0c;不仅不用受时间和空间的限制&#xff0c;还能拥有身临其境般的体验&#xff0c;使得我们足不出户就能随时随地学习、传承红色文化。 很多党建展厅都是比较传统的&#xff0c;没有运用…

php - fpm 请求达到max_children最大值后,新进入的请求工作流程

前言 偶然之间想了解下&#xff0c;php-fpm 请求达到max_children最大值后&#xff0c;新进入的请求怎么办&#xff1f;是抛出502还是等待前面的请求完成后&#xff0c;再将请求交给处理完毕的进程处理呢。 准备工作 运行环境&#xff1a;LNMP php 版本&#xff1a;php8.1 …

零基础教程:使用yolov8训练自己的目标检测数据集

1.前言 Ultralytics YOLOv8 是一款前沿、最先进&#xff08;SOTA&#xff09;的模型&#xff0c;基于先前 YOLO 版本的成功&#xff0c;引入了新功能和改进&#xff0c;进一步提升性能和灵活性。YOLOv8 设计快速、准确且易于使用&#xff0c;使其成为各种物体检测与跟踪、实例…

联合办公空间适合的人群类型

联合办公空间适合以下几类群体租赁&#xff1a; 创业公司和初创企业&#xff1a;联合办公为创业公司和初创企业提供了一个低成本、低风险的办公场所&#xff0c;这些公司通常不需要承担长期租赁办公室的高成本和风险。自由职业者和个体工作者&#xff1a;联合办公提供了一个具…

【图像处理】模板匹配的学习笔记

OpenCV的模板匹配算法 cv.TM_CCOEFFcv.TM_CCOEFF_NORMEDcv.TM_CCORRcv.TM_CCORR_NORMEDcv.TM_SQDIFFcv.TM_SQDIFF_NORMED 匹配代码模板 image cv2.imread(r"scene.png", cv2.IMREAD_GRAYSCALE) template cv2.imread(r"element.png", cv2.IMREAD_GRAYSC…

计算机行业前景展望

计算机行业的前景展望是非常广阔的。随着技术的快速发展和应用领域的不断拓展&#xff0c;计算机行业将继续扮演着重要的角色。以下是一些计算机行业前景的关键方面&#xff1a; 人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;&#xff1a;AI和ML技术…

STM32G0 定时器PWM DMA输出驱动WS2812配置 LL库

通过DMA方式输出PWM模拟LED数据信号 优点&#xff1a;不消耗CPU资源 缺点&#xff1a;占用内存较大 STM32CUBEMX配置 定时器配置 定时器通道&#xff1a;TIM3 CH2 分频&#xff1a;0 重装值&#xff1a;79&#xff0c;芯片主频64Mhz&#xff0c;因此PWM输出频率&#xff1a…

Opendds概念介绍

刚学习opendds&#xff0c;需要建立几个概念。 opendds是什么&#xff1f; 答&#xff1a;opendds是消息中间件。 opendds的作用是什么&#xff1f; 答&#xff1a;opendds是一款消息中间件&#xff0c;开发者利用opendds在不同节点之间进行数据通信或者交互时无需考虑通信…