【蓝桥杯 2025 省 A 扫地机器人】题解

题目链接

如果 ∀ t i = 0 \forall ti = 0 ∀ti=0,直接输出 0 0 0。

由于题中所给是 n n n 个点 n n n 条边的 连通图,我们可以得到这是一棵基环树。

我们把答案分为三类:

  • 以环上某点 i i i 为根的树的直径;
  • 从某个树的叶子出发到达环上的根 i i i,绕过 整个环,回到 i i i,再走向 i i i 的另一个儿子直到叶子;
  • 从某个树的叶子出发到达环上的根 i i i,不绕过 整个环,走到环上另一点 j j j,再走向 j j j 的一个儿子直到叶子。

首先,我们找到基环树的环,环长为 m m m,然后对于每颗树,都预处理出 m d e p i \rm{mdepi} mdepi 和 s d e p i \rm{sdepi} sdepi,分别表示以 i i i 为根的树的深度最大值和次大值,这个一次 d f s \rm{dfs} dfs 就能做到。

然后对于长度为 m m m 的环,设顺时针(或逆时针)第 i i i 个点为 v e c i , i ∈ 0 , m ) \\rm{vec\[i}, \ i \in 0, m) vec\[i, i∈0,m),我们破环成链,令 v e c \[ i + m = v e c i \rm{veci + m = veci} veci+m=veci,再做一个前缀和,即

s i + 1 = s i + t v e c \[ i ] , i ∈ 0 , 2 m ) . \\rm{s\[i + 1 = si + tvec\[i]}, \ i \in 0, 2m). s\[i+1=si+tvec\[i], i∈[0,2m).

这样三类的答案就分别是:

  • 第一类:
    m d e p i + s d e p i + t i , ∀ i ∈ 0 , n ) . \\rm{mdep\[i + sdepi + ti}, \ \forall i \in 0, n). mdep\[i+sdepi+ti, ∀i∈[0,n).
  • 第二类:
    m d e p v e c \[ i ] + s d e p v e c \[ i ] + s m , ∀ i ∈ 0 , m ) . \\rm{mdep\[vec\[i] + sdepvec\[i] + sm, \ \forall i \in 0, m)}. mdep\[vec\[i]+sdepvec\[i]+sm, ∀i∈[0,m).
  • 第三类:
    m d e p v e c \[ i ] + ( s i + 1 − s j ) + m d e p v e c \[ j ] , 0 ≤ j < i < 2 m , i − j < m . \rm{mdepvec\[i] + (si + 1 - sj) + mdepvec\[j]}, \ 0 \leq j < i < 2m, \ i - j < m. mdepvec\[i]+(si+1−sj)+mdepvec\[j], 0≤j<i<2m, i−j<m.

第一、二类要求最大值直接 O ( n ) O(n) O(n) 遍历即可,第三类则需要对式子变形,变为

( m d e p v e c \[ i ] + s i + 1 ) + ( m d e p v e c \[ j ] − s j ) , \rm{(mdepvec\[i] + si + 1) + (mdepvec\[j] - sj)}, (mdepvec\[i]+si+1)+(mdepvec\[j]−sj),

这样一来对每个 i i i,就只要维护 m d e p v e c \[ j ] − s j \rm{mdepvec\[j] - sj} mdepvec\[j]−sj 的最大值,其中

j ∈ [ max ⁡ ( 0 , i − m + 1 ) , i ) , \rm{j \in [\max(0, i - m + 1), \ i),} j∈[max(0,i−m+1), i),

这可以用单调队列实现,时间复杂度 O ( n ) O(n) O(n)。

时间复杂度 O ( n ) O(n) O(n)

C++ Code

cpp 复制代码
#include <bits/stdc++.h>

template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
    for (auto &x: v) {
        is >> x;
    }
    return is;
}
template<class T>
void chmax(T &a, T b) {
    if (a < b) {
        a = b;
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;

    std::vector<int> t(n);
    std::cin >> t;

    if (std::ranges::count(t, 0) == n) {
        std::cout << 0 << "\n";
        return 0;
    }

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

    int idx = 0;
    std::vector<int> vec;
    vec.reserve(n);
    std::vector<bool> ins(n);
    std::vector<bool> cyc(n);
    std::vector<int> dfn(n, -1);
    std::vector<int> pre(n, -1);
    auto init = [&](auto &&self, int x) -> void {
        dfn[x] = idx++;
        ins[x] = true;
        for (int y: adj[x]) {
            if (y == pre[x]) {
                continue;
            }
            if (dfn[y] == -1) {
                pre[y] = x;
                self(self, y);
            } else if (ins[y]) {
                for (int i = x; ; i = pre[i]) {
                    vec.push_back(i);
                    cyc[i] = true;
                    if (i == y) {
                        break;
                    }
                }
            }
        }
        ins[x] = false;
    };
    init(init, 0);

    std::vector<int> mdep(n);
    std::vector<int> sdep(n);
    std::ranges::fill(pre, -1);
    auto tree = [&](auto &&self, int x) -> void {
        for (int y: adj[x]) {
            if (y == pre[x] or cyc[y]) {
                continue;
            }
            pre[y] = x;
            self(self, y);
            if (mdep[x] < mdep[y] + t[y]) {
                sdep[x] = mdep[x];
                mdep[x] = mdep[y] + t[y];
            } else if (sdep[x] < mdep[y] + t[y]) {
                sdep[x] = mdep[y] + t[y];
            }
        }
    };

    int res = 0;
    for (int i: vec) {
        tree(tree, i);
        chmax(res, mdep[i] + sdep[i]);
    }
    int dia = 0;
    for (int i = 0; i < n; i++) {
        chmax(dia, mdep[i] + sdep[i] + t[i]);
    }
    
    int m = vec.size();
    vec.insert(vec.end(), vec.begin(), vec.end());

    std::vector<int> s(2 * m + 1);
    for (int i = 0; i < 2 * m; i++) {
        s[i + 1] = s[i] + t[vec[i]];
    }
    int ans = std::max(dia, res + s[m]);

    std::deque<int> q;
    for (int i = 0; i < 2 * m; i++) {
        int j = vec[i];
        while (not q.empty() and i - q.front() >= m) {
            q.pop_front();
        }
        if (not q.empty()) {
            chmax(ans, mdep[j] + s[i + 1] + mdep[vec[q.front()]] - s[q.front()]);
        }
        while (not q.empty() and mdep[vec[q.back()]] - s[q.back()] <= mdep[j] - s[i]) {
            q.pop_back();
        }
        q.push_back(i);
    }

    std::cout << ans << "\n";

    return 0;
}
相关推荐
Godspeed Zhao11 分钟前
现代智能雷达技术19——算法(5)
算法
(Charon)12 分钟前
【C++面试】RAII到底是什么:从资源管理理解C++对象生命周期
c++·算法·面试
无名猿15 分钟前
成员初始化列表与初始化顺序陷阱:按声明顺序,不是书写顺序
c++·现代c++·语法基础
Omics Pro21 分钟前
之江实验室NAR|虚拟细胞3阶段训练范式
数据库·人工智能·算法·机器学习·自然语言处理
Tisfy27 分钟前
LeetCode 0678.有效的括号字符串:O(n)+O(1)一次遍历
算法·leetcode·字符串·题解·贪心·括号匹配
91刘仁德30 分钟前
传输层协议深度拆解:端口寻址、UDP 报文与 TCP 可靠性机制全解析
linux·网络·c++·网络协议·tcp/ip·udp·c
小O的算法实验室31 分钟前
IEEE TEVC,学习辅助的搜索路径重构进化算法
学习·算法·重构
Liuchang091135 分钟前
洛谷 P2670 [NOIP 2015 普及组] 扫雷游戏
c++·算法·游戏
言乐61 小时前
Python体现逻辑回归和决策树的区别
开发语言·python·算法·决策树·逻辑回归
顶点多余1 小时前
C/C++常见面试题
开发语言·c++