[题解] [SDOI2011] 消防

news2025/10/29 3:58:18

[题解] [SDOI2011] 消防

tag: 图论树的直径
题目链接(洛谷):https://www.luogu.com.cn/problem/P2491

题目描述

给定一棵 n n n 个节点的树,第 i i i 条边有边权 z i z_i zi 。要求找到树上一条长度不大于 s s s 的简单路径,使得不在路径上的点到该路径的最大距离最小。
数据范围: 1 ≤ n ≤ 3 × 1 0 5 , 0 ≤ z i ≤ 1 0 3 1 \leq n \leq 3 \times 10^5, 0 \leq z_i \leq 10^3 1n3×105,0zi103

题解

不难得出结论:如果没有 s s s 的限制,则选择该树的直径最优。进一步考虑长度为 s s s 的限制对答案的影响,可以发现即使在限制长度的条件下,答案的路径依然是直径的子集。在此不做严格证明,可以尝试采用在直径上删边、在点上扩展边的方式验证。因此,我们枚举在直径中的路径区间来解决此问题。对于直径,可以使用两次 DFS 的方式求得直径上的所有点,及其中各相邻点之间的距离,这个过程的时间复杂度是 O ( n ) O(n) O(n)。对于区间枚举,我们使用双指针,从左到右枚举区间的左端点,利用 l ≤ s l \leq s ls 的条件确定右端点即可,这个过程的时间复杂度也是 O ( n ) O(n) O(n)

那么新的问题是,对于一条确定的直径上的路径,如何求得距离该路径最远的点的距离。我们按照将直径缩短的思路思考。最初始的情况,我们要考虑不在直径上的点到直径的距离,可以利用 DFS ,从每个直径上的点向不在直径上的点遍历,在 O ( n ) O(n) O(n) 的时间复杂度内求出每个不在直径上的点到直径的最大值,我们称之为初始最长路径,这些初始最长路径的最大长度就是该问题的初始答案。接下来考虑直径缩短,我们又可以得到一个新的结论:在路径从直径上缩短时,除初始最长路径之外,新的最长路径一定是缩短后的路径的两端到直径的两端的距离的较大值。这个结论也不难验证。因此,我们只需在双指针枚举时动态维护这个长度,同时更新直径上的答案即可。最终的答案是初始答案和直径上的较大值。

AC 代码

//
// Created by wxy3265 on 2024/10/3.
//
#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
using namespace std;

const int MAXN = 2e7 + 5e6;
const int MAXM = 2e7 + 5e6;

// 建图
int first[MAXN], v[MAXM], nt[MAXM], w[MAXM];
int te;
inline void addEdge(int x, int y, int ww) {
    nt[++te] = first[x];
    first[x] = te;
    v[te] = y;
    w[te] = ww;
}

// 第一次 DFS 找到直径的一端
int maxd, maxdi;
void dfs1(int x, int fa, int step) {
    if (step > maxd) maxd = step, maxdi = x;
    for (int eo = first[x]; eo; eo = nt[eo]) {
        const int ep = v[eo];
        if (ep == fa) continue;
        dfs1(ep, x, step + w[eo]);
    }
}

// 第二次 DFS 找到直径,同时求出直径上相邻点及距离(nxt、nw)
int f[MAXN], nxt[MAXN], nw[MAXN];
void dfs2(int x, int fa, int step) {
    for (int eo = first[x]; eo; eo = nt[eo]) {
        const int ep = v[eo];
        if (ep == fa) continue;
        dfs2(ep, x, step + w[eo]);
        if (f[ep] > f[x]) {
            f[x] = f[ep];
            nxt[x] = ep;
            nw[x] = w[eo];
        }
    }
    if (!f[x]) f[x] = step;
}

// 第三次 DFS 求出从各直径上的点出发不经过其他直径上的点的最远距离
bool id[MAXN];
int mx[MAXN];
void dfs3(int x, int fa) {
    for (int eo = first[x]; eo; eo = nt[eo]) {
        const int ep = v[eo];
        if (ep == fa || id[ep]) continue;
        dfs3(ep, x);
        mx[x] = max(mx[x], mx[ep] + w[eo]);
    }
}

int q[MAXN], head = 0, tail = 0;
signed main() {
    // 读入数据
    int n, s;
    cin >> n >> s;
    for (int i = 1; i <= n - 1; i++) {
        int x, y, ww;
        cin >> x >> y >> ww;
        addEdge(x, y, ww);
        addEdge(y, x, ww);
    }
    // 求直径
    dfs1(1, 0, 0);
    dfs2(maxdi, 0, 0);
    int tot = 0;
    head = 1;
    for (int i = maxdi; i != 0; i = nxt[i]) {
        q[++tail] = i;
        tot += nw[i];
        id[i] = true;
    }
    // 求初始答案
    int r = tail, now = tot, ans = 0, tmp = tot;
    for (int i = 1; i <= n; i++) {
        if (id[i]) {
            dfs3(i, 0);
            ans = max(ans, mx[i]);
        }
    }
    // 双指针遍历
    int dr = 0, dl = 0;
    while (head <= s) {
        while (r >= head && now > s) {
            r--;
            now -= nw[q[r]];
            dr += nw[q[r]];
        }
        tmp = min(tmp, max(dr, dl));
        dl += nw[q[head]];
        now -= nw[q[head]];
        head++;
        while (r <= tail && now + nw[q[r]] <= s) {
            now += nw[q[r]];
            dr -= nw[q[r]];
            r++;
        }
    }
    cout << max(ans, tmp) << '\n';
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2186929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaSE——面向对象8:Object类详解(==与equals的区别、hashCode、toString方法)

目录 一、与equals()的区别 (一)是一个比较运算符 (二)equals是Object类中的方法&#xff0c;只能判断引用类型 (三)equals方法重写练习 1.练习1 2.练习2 3.练习3 二、hashCode方法 三、toString方法 1.默认返回&#xff1a;全类名(包名类名)哈希值的十六进制 (1)不…

VS编译器实用调试技巧

一.什么是bug bug本意是"昆虫"或"虫子&#xff3d;&#xff0c;现在一般是指在电脑系统或程序中&#xff0c;隐藏着的一些未被发现的缺陷或问题&#xff0c;简称程序漏洞。“Bug"的创始人格蕾丝&#xff0e;赫柏&#xff08;Grace Murray Hopper)&#xff…

算法笔记(七)——哈希表

文章目录 两数之和判定是否互为字符重排存在重复元素存在重复元素 II字母异位词分组 哈希表&#xff1a;一种存储数据的容器&#xff1b; 可以快速查找某个元素&#xff0c;时间复杂度O(1)&#xff1b; 当频繁查找某一个数时&#xff0c;我们可以使用哈希表 创建一个容器&#…

堆的代码和基础知识

堆的向上和向下调整-CSDN博客 1.堆的基础知识 2.堆的代码 Heap.h #pragma once #include<stdio.h> #include<assert.h> #include<stdlib.h> #include<stdbool.h> #include<time.h>// typedef int HPDataType; typedef struct Heap {HPDataTy…

电场磁场,能量密度和平均值(定义式是用实数场计算的,不能直接将定义式里面修改为复数场)

能量密度的定义式&#xff0c;都是实数场 平均能量密度&#xff0c;里面的是复数表示的场。具体推导类似坡印廷矢量 、

4.6章节python中空语句pass保留字作用

在Python中&#xff0c;pass 是一个空语句&#xff0c;它什么也不做。它通常用作占位符&#xff0c;在需要语法上需要一个语句但程序逻辑上不需要执行任何操作的地方。 1.占位符&#xff1a;在编写代码时&#xff0c;如果你还没有决定某个部分应该做什么&#xff0c;可以先用 p…

[深度学习][python]yolov11+bytetrack+pyqt5实现目标追踪

【算法介绍】 YOLOv11、ByteTrack和PyQt5的组合为实现高效目标追踪提供了一个强大的解决方案。 YOLOv11是YOLO系列的最新版本&#xff0c;它在保持高检测速度的同时&#xff0c;通过改进网络结构、优化损失函数等方式&#xff0c;提高了检测精度&#xff0c;能够同时处理多个…

android RadioButton 设置颜色无效

原因好像是 RadioButton 自动被渲染为 MaterialRadioButton 设置颜色使用这个属性 app:buttonTint“color/black” material-components-android/docs/components/RadioButton.md at master material-components/material-components-android (github.com)https://github.…

【MySQL】SQL介绍+基础+DDL+数据备份+还原

目录 一、DDL建库建表 1. 数据库 2. 内部4特征 3. 外部4特征 4. 数据库结构 5. SQL语句分类&#xff08;重点&#xff09; 6. 注意 7. 数据库表的字段类型 8. 存储引擎 9. 数据库表的操作 二、三范式 1. 什么是范式 2. 约束作用 3. 三范式 4. 第一范式&#xff…

Python从入门到高手4.2节-掌握循环控制语句

目录 4.2.1 理解循环控制 4.2.2 for循环结构 4.2.3 循环结构的else语句 4.2.4 while循环结构 4.2.5 循环结构可以嵌套 4.2.6 国庆节吃好玩好 4.2.1 理解循环控制 我们先来搞清楚循环的含义。以下内容引自汉语词典: 循环意指往复回旋&#xff0c;指事物周而复始地运动或变…

Sharp.js:简单而又实用的图像处理库

前言 在现代Web开发中&#xff0c;图像处理是一个不可或缺的部分。 前端开发者经常需要处理图像&#xff0c;以确保它们在不同的设备和分辨率上都能保持良好的显示效果。 sharp.js是一个高性能的Node.js模块&#xff0c;它利用了libvips库&#xff0c;提供了快速且高效的图像…

网安学习(js漏洞挖掘)

内容来自bili白帽大法师白帽大法师的个人空间-白帽大法师个人主页-哔哩哔哩视频 (bilibili.com) 四种方式 目录 1、JS中存在插件名字&#xff0c;根据插件找到相应的漏洞直接利用 2、JS中存在一些URL链接&#xff0c;根据URL链接找到相应的页面进一步测试和利用 3、JS中存…

《软件工程概论》作业一:新冠疫情下软件产品设计

课程说明&#xff1a;《软件工程概论》为浙江科技学院2018级软件工程专业在大二下学期开设的必修课。课程使用《软件工程导论&#xff08;第6版&#xff09;》&#xff08;张海藩等编著&#xff0c;清华大学出版社&#xff09;作为教材。以《软件设计文档国家标准GBT8567-2006》…

Python案例--水仙花数的探索之旅

一、引言 水仙花数&#xff0c;也称为阿姆斯特朗数&#xff0c;是一种特殊的三位数&#xff0c;其各位数字的立方和等于其本身。例如&#xff0c;153就是一个水仙花数&#xff0c;因为 135333153135333153。这种数字的发现不仅展示了数字的内在美&#xff0c;也激发了人们对数…

STM32编码器接口解析及抗噪声措施探讨

1. 引言 在现代控制系统中&#xff0c;编码器扮演着非常重要的角色。它就像一个精密的测量工具&#xff0c;可以告诉我们机械部件的位置和运动状态。在STM32微控制器中&#xff0c;编码器接口可以轻松地与各种编码器连接&#xff0c;实现精确的控制。我将在这里探讨STM32编码器…

unity 默认渲染管线材质球的材质通道,材质球的材质通道

标准渲染管线——材质球的材质通道 文档&#xff0c;与内容无关&#xff0c;是介绍材质球的属性的。 https://docs.unity3d.com/2022.1/Documentation/Manual/StandardShaderMaterialParameters.html游戏资源中常见的贴图类型 https://zhuanlan.zhihu.com/p/260973533 十大贴图…

flutter_鸿蒙next(win)环境搭建

第一步 拉取鸿蒙版本flutterSDK仓库 仓库地址&#xff1a;OpenHarmony-SIG/flutter_flutter 第二步 找到拉取的仓库中的README.md 并根据说明配置环境 第三步 配置好环境变量之后 用管理员开启cmd 输入&#xff1a;flutter dcotor 并查看此时flutter所支持的系统 包括&…

Cpp::STL—string类的模拟实现(12)

文章目录 前言一、string类各函数接口总览二、默认构造函数string(const char* str "");string(const string& str);传统拷贝写法现代拷贝写法 string& operator(const string& str);传统赋值构造现代赋值构造 ~string(); 三、迭代器相关函数begin &…

leetcode打卡001-约瑟夫问题

约瑟夫问题 其背景故事是关于一组人站成一个圈&#xff0c;从某个人开始报数&#xff0c;每数到特定数字的人将被淘汰出圈&#xff0c;然后从被淘汰人的下一个人重新开始报数&#xff0c;直到最后剩下一个人。问题的目标是确定最后剩下的那个人在最初的位置。 关键词 递归&a…

HCIP-HarmonyOS Application Developer 习题(四)

1、以下哪个Harmonyos的AI能力可以提供文档翻拍过程中的辅助增强功能? A.文档检测矫正 B.通用文字识别 C.分词 D.图像超分辨率 答案&#xff1a;A 分析&#xff1a;文档校正提供了文档翻拍过程的辅助增强功能&#xff0c;包含两个子功能&#xff1a; 文档检测&#xff1a;能够…