[BJWC2010] 严格次小生成树 简单梳理和整理

2023-05-16

https://www.luogu.com.cn/problem/P4180

这篇文章将会默认读者已经掌握了LCA,kruskal等相关基础知识点

  • 考虑最小生成树的 k r u s k a l kruskal kruskal算法,我们构造好一颗最小生成树以后,如何找到次小?容易想到,我们依然按照贪心策略,再加入一条边权最小的边,那么此时一定出现了环,那么我们把这个环上除了刚才加进来的这条边以外最大的那条边删除掉,得到的就是次小生成树。
  • 如何证明,考虑这样几条边 a , b , c , d , ( a < b < c < d ) a,b,c,d,(a<b<c<d) a,b,c,d,(a<b<c<d),假设现在 a , b a,b a,b已经在最小生成树里面,那么我们现在要把 c c c加进去,肯定是把 b b b换下来最优;如果这样不最优,我加个 d d d,那也得把 b b b换下来,那还不如刚才的情况,所以这样可以得到次小
  • 那怎么保证严格次小呢?只需要维护一个最大和次大就好了;考虑为什么会不严格,就是因为换下来的边有可能和加进来的那条边长度相等,所以如果发现相等,只要知道次小边是谁直接换这个就好了;如果不相等就换最大边
  • 这里不画图应该也容易理解

那么现在考虑如何实现,怎么高效的维护最大和次大呢?如果暴力每次都是 O ( n ) O(n) O(n)的,肯定不行,我要考虑一个 O ( 1 ) O(1) O(1)的方法,那就是倍增,预处理出来所有节点之间的父子关系,从哪出发都行,根据 S T ST ST表或者 L C A LCA LCA思想,同时求整棵树上的父子关系、边权最大、次大倍增数组,共计三个数组,这样信息预处理就解决了

  1. 建立最小生成树,同时标记已经用过的边
  2. 从任意一个节点开始 D f s Dfs Dfs,统计节点深度,以及三个倍增数组,分别为 f [ i ] [ j ] , g [ i ] [ j ] , h [ i ] [ j ] f[i][j],g[i][j],h[i][j] f[i][j],g[i][j],h[i][j]表示父子关系、最大、次大,其中 i i i表示节点编号, j j j表示父子之间的传递代数(传宗接代的代,懂的都懂)
  3. 开始加边,设端点为 u , v u,v u,v,求出 u u u v v v L C A LCA LCA,求 u → L C A u\rightarrow LCA uLCA v → L C A v\rightarrow LCA vLCA这两条链上的可以替换的边,求形成的生成树的边权和,取最小值,一直计算到结束

把DFS的程序单独拿出来解释一下,其余部分都比较常规

void Dfs(int u, int fa, ll w){
    dep[u] = dep[fa] + 1;
    f[u][0] = fa;
    g[u][0] = w;
    h[u][0] = -INF;
    for(int i=1;i<=20;i++){
        f[u][i] = f[f[u][i - 1]][i - 1];
        g[u][i] = max(g[u][i - 1], g[f[u][i - 1]][i - 1]);
        h[u][i] = max(h[u][i - 1], h[f[u][i - 1]][i - 1]);
        if(g[u][i - 1] > g[f[u][i - 1]][i - 1]){
            h[u][i] = max(h[u][i], g[f[u][i - 1]][i - 1]);
        }else if(g[u][i - 1] < g[f[u][i - 1]][i - 1]){
            h[u][i] = max(h[u][i], g[u][i - 1]);
        }
    }
    for(int i=head[u];~i;i=edge[i].next){
        int v = edge[i].to;
        if(v == fa) continue;
        Dfs(v, u, edge[i].val);
    }
}
  • 首先统计深度,然后我设置了 20 20 20代,大概是 2 20 = 1024 × 1024 2^{20}=1024\times1024 220=1024×1024,范围足够,重点关注如何求取 g g g h h h两个倍增数组
  • 首先倍增不能少,也就是 g [ u ] [ i ] = m a x ( g [ u ] [ i − 1 ] , g [ f [ u ] [ i − 1 ] ] [ i − 1 ] ) g[u][i]=max(g[u][i-1],g[f[u][i-1]][i-1]) g[u][i]=max(g[u][i1],g[f[u][i1]][i1])这个递推过程就是 u u u往上第 2 i 2^i 2i代的求取过程,显然就是 2 i − 1 2^{i-1} 2i1代往上 2 i − 1 2^{i-1} 2i1代,接下来的判断就是在找次大,因为最大没什么好说的就一直 m a x max max就好了,次大的意思是严格小于最大的最大数,所以这两部分我要比较一下哪部分更大,如果一样大那就没有,所以题目保证一定存在严格次小生成树,不用担心;否则取较小的一部分作为次大,也就是 u u u到它爷爷的次大应该在 u u u到他爸爸的最大和 u u u爸爸到 u u u爷爷的最大里面选择一个相对较小的,这样应该就可以理解这个过程了
  • 完整程序如下
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int MAXN = 1e6 + 100;
const ll INF = 1e16;
struct st{
    int u, v;
    ll w;
    bool operator < (const st &B)const{
        return w < B.w;
    }
}s[MAXN];
struct Edge{
    int next;
    int to;
    ll val;
}edge[MAXN];
int head[MAXN];
int cnt;
void Add_Edge(int u, int v, ll w){
    edge[cnt].next = head[u];
    edge[cnt].to = v;
    edge[cnt].val = w;
    head[u] = cnt++;
}
int f[MAXN][30];
ll g[MAXN][30];
ll h[MAXN][30];
int dep[MAXN];
int LCA(int u, int v){
    if(dep[u] < dep[v]) swap(u, v);
    for(int i=20;i>=0;i--){
        if(dep[f[u][i]] >= dep[v]){
            u = f[u][i];
        }
    }
    if(u == v) return u;
    for(int i=20;i>=0;i--){
        if(f[u][i] != f[v][i]){
            u = f[u][i];
            v = f[v][i];
        }
    }
    return f[u][0];
}
int fa[MAXN];
int FIND(int x){
    return x == fa[x] ? x : fa[x] = FIND(fa[x]);
}
int vis[MAXN];
ll Kruskal(int n, int m){
    ll sum = 0;
    int num = 0;
    for(int i=1;i<=m;i++){
        int u = FIND(s[i].u);
        int v = FIND(s[i].v);
        ll w = s[i].w;
        if(u == v) continue;
        Add_Edge(s[i].u, s[i].v, w);
        Add_Edge(s[i].v, s[i].u, w);
        vis[i] = 1;
        fa[u] = v;
        num += 1;
        sum += w;
        if(num == n - 1) break;
    }
    return sum;
}
void Dfs(int u, int fa, ll w){
    dep[u] = dep[fa] + 1;
    f[u][0] = fa;
    g[u][0] = w;
    h[u][0] = -INF;
    for(int i=1;i<=20;i++){
        f[u][i] = f[f[u][i - 1]][i - 1];
        g[u][i] = max(g[u][i - 1], g[f[u][i - 1]][i - 1]);
        h[u][i] = max(h[u][i - 1], h[f[u][i - 1]][i - 1]);
        if(g[u][i - 1] > g[f[u][i - 1]][i - 1]){
            h[u][i] = max(h[u][i], g[f[u][i - 1]][i - 1]);
        }else if(g[u][i - 1] < g[f[u][i - 1]][i - 1]){
            h[u][i] = max(h[u][i], g[u][i - 1]);
        }
    }
    for(int i=head[u];~i;i=edge[i].next){
        int v = edge[i].to;
        if(v == fa) continue;
        Dfs(v, u, edge[i].val);
    }
}
ll Get(int u, int v, ll mx){
    ll ans = -INF;
    for(int i=20;i>=0;i--){
        if(dep[f[u][i]] >= dep[v]){
            if(mx != g[u][i]){
                ans = max(ans, g[u][i]);
            }else{
                ans = max(ans, h[u][i]);
            }
            u = f[u][i];
        }
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m;
    memset(head, -1, sizeof head);
    cin >> n >> m;
    for(int i=1;i<=n;i++) fa[i] = i;
    for(int i=1;i<=m;i++){
        int u, v;
        ll w;
        cin >> u >> v >> w;
        s[i].u = u;
        s[i].v = v;
        s[i].w = w;
    }sort(s + 1, s + 1 + m);
    ll sum = Kruskal(n, m);
    Dfs(2, 0, 0);
    ll ans = INF;
    for(int i=1;i<=m;i++){
        if(!vis[i]){
            int u = s[i].u;
            int v = s[i].v;
            int lca = LCA(u, v);
            ll s1 = Get(u, lca, s[i].w);
            ll s2 = Get(v, lca, s[i].w);
            // cout << s1 << ' ' << s2 << '\n';
            ans = min(ans, sum - max(s1, s2) + s[i].w);
        }
    }
    cout << ans;
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[BJWC2010] 严格次小生成树 简单梳理和整理 的相关文章

  • Linux系统安装FFmpeg以及依赖库

    最近这两周都在搞FFmpeg的安装 xff0c 先是在windows平台上做了一个rtsp音视频流采集程序 但总监必须要我运行在Linux 平台上 xff0c 没办法 xff0c 就这样开始了我的噩梦 小白一个 xff0c 大神勿喷 附件中
  • armbian换源

    先科普一下源格式 deb http mirrors aliyun com ubuntu ports xenial main 源类型 地址 系统版本 包范围 src源 没看源码需求可以注释以加快速度 一般换源直接更换地址即可 系统版本要和自己
  • c++报错合集

    c 43 43 报错合集 未定义标识符mkdir不存在从string到const char 的转换函数C4996 39 fopen 39 This function or variable may be unsafe Consider us
  • 直方图中最大矩形面积

    原文地址 xff1a http www geeksforgeeks org largest rectangle under histogram 注意 xff1a 本文并未对原文完整翻译 xff0c 而是结合原文并根据本人理解写出 xff0c
  • 常用的第三方api汇总[获取天气]

    这里mark一下自己经常用第三方api xff0c 非商用 xff0c 适合自己学习测试使用 例如js里的fetch xff0c 不要恶意访问 xff0c 后续会慢慢补充 1 随机用户 GET请求 JSON格式 https api rand
  • 私有服务器gitlab15.1.1-ce.0.el7版本添加新用户

    1 在menu下找到admin 2 进入admin后 xff0c 点击new user 3 进入new user之后 xff0c 以下三项必填 xff0c 其中第二项不能为中文 4 之后下划 xff0c 点击creature user 系统
  • Django 项目初始化

    文章目录 初始化流程1 环境准备1 1 制定规范1 2 建立虚拟环境1 3 安装 virtualenv1 4 激活虚拟环境1 5 退出虚拟环境1 6 安装 Django 2 创建项目 project3 创建应用 application 初始
  • 优酷路由宝 OpenWrt 刷机

    优酷路由宝 OpenWrt 刷机 资源列表 优酷土豆路由宝已获取 root 权限的版本固件 下载 https biaowong lanzouu com iChJt031yeud 密码 e6otBreed 刷机工具 下载 https biao
  • 谈一下两次CSP认证从180分到380分的感想

    最近联系我的小可爱们比较多 xff0c 我用qq建了一个ccf csp考试交流群 xff0c 群号673612216 xff0c 如果感觉有用可以加一下哦 欢迎访问我的CCF认证考试题解目录哦 https blog csdn net ric
  • Deepin Linux v20+安装Calibre官方最新版的方法

    电子书阅读 管理 编辑神器 xff0c 官方提供了非常简单高效的安装脚本 xff0c 下面一句指令就可以快速安装 xff0c 非常方便 xff0c 大家可以不必安装商店里面的版本 xff0c 直接安装最新版的 安装命令 xff1a sudo
  • 硬盘安装Debian与Xp双系统

    发个debian 6 0的简单安装教程 2009年10月写了个 debian lenny的简单安装教程 xff0c 前段时间一直盼望的6 0 squeeze终于正式发布了 xff0c 所以在lenny的教程基础上进行了修改 xff0c 以满
  • c语言链表及其基本操作

    链表及其基本操作 文章目录 链表及其基本操作 一 链表是什么 xff1f 二 链表是如何实现的1 创建链表2 输出链表 三 基本操作 xff08 增删改查插 xff09 1 查找结点2 删除结点3 插入结点4 清空结点 做为一名 新生蒟蒻来
  • 湖南大学第十六届程序设计竞赛

    湖南大学第十六届程序设计竞赛 https ac nowcoder com acm contest 18196 description D 遇到这种题 xff0c 其实可以去大胆点找规律 正解是对于排位的期望 xff0c 我们只需要在意排的位
  • VS2010中CString Format出错

    VS2010中 Format 用法 xff1a 我在项目中需要实现一个字符串的转化 xff0c 代码如下 xff1a CString mess int x y x 61 640 y 61 480 mess Format 34 当前为 xff
  • 数据库MySQL安装方法:官网下载安装、国内镜像源安装

    一 官网下载安装 xff08 MySQL Download MySQL Yum Repository xff09 下载rpm包 xff0c 上传到虚拟机上 xff08 rz命令 xff09 root 64 localhost ls 在官网下
  • 输出函数print的用法

    print函数的作用 xff1a 可以将想要展示的内容输出在d IDLE上或者输出在文件中 print xff08 xff09 函数的使用 xff1a 1 print xff08 xff09 函数输出的内容可以是数字 2 print xff
  • 2021“MINIEYE杯”中国大学生算法设计超级联赛

    2021 MINIEYE杯 中国大学生算法设计超级联赛 1006 Given a sequence of integers of length n find the shortest consecutive subsequence witc
  • ac自动机

    https blog csdn net lleozhang article details 82782723 https www cnblogs com vongang archive 2012 07 24 2606494 html htt
  • 基环树 最大独立集

    基环树 xff0c 也是环套树 xff0c 简单地讲就是树上在加一条边 它形如一个环 xff0c 环上每个点都有一棵子树的形式 因此 xff0c 对基环树的处理大部分就是对树处理和对环处理 显然 xff0c 难度在于后者 在基环树中 xff
  • 有向图无向图找环

    https codeforces com contest 1607 problem F 练习题 xff08 有向图 题解 xff1a https www cnblogs com handwer p 15506706 html E8 B5 B

随机推荐

  • 《机器人知识结构图》思维导图,探索人工智能领域

    随着时代快速发展 xff0c 经济快速进步的趋势 xff0c 人工智能领域越来越被重视 xff0c 它是一门边缘学科 xff0c 属于自然科学和社会科学的交叉界限 实际应用的课程非常多 他的研究范畴又包括了自然语言处理 xff0c 知识表现
  • 微信小程序的两种视频录制方式

    曾有小伙伴询问小编能不能在小程序内实现视频录制 xff0c 今天小编就来给大家分享小程序视频录制两种方式 方法一 wx chooseVideo xff0c 这个api微信会在下方弹出选择视频和拍摄的两种选项 xff0c 因为这次主要是讲拍摄
  • 如何使用app原生上传替代uniapp的uploadfile接口

    uniapp简介 uniapp是近两年来比较火的号称开发者编写一套代码 xff0c 可发布到iOS Android Web xff08 响应式 xff09 以及各种小程序的一个平台 xff0c 它提供了各种丰富的API文档让开发者快速的完成
  • 如何用electron高度自定义制一个系统菜单栏?

    背景 最近在做一个实时聊天的PC客户端 xff0c 遇到这样一个任务 xff0c 在客户端接收到其他用户消息的时候要闪烁系统托盘图标 xff0c 并且在鼠标滑到系统托盘的时候显示未读消息的菜单栏 xff08 对 xff0c 就是类似QQ的消
  • OPENVIDU实现网络质量检测统计

    1 前言 在WebRTC中 xff0c 我们需要对当前的音视频情况进行监控 xff0c 便于对音视频质量有一个了解 xff0c 同时可以用来分析定位音视频卡顿模糊等问题 WebRTC提供了一个标准的解决方案 xff1a 标准详情 基于此标准
  • OPENVIDU实现同一用户同时发布多个流媒体

    1 前言 OPENVIDU这个库暂时是不支持在同一个会议室里面 xff0c 同一个用户同时发布多个媒体流的 但在实际工作中有这种需要 xff0c 比如用户A既要发布摄像机媒体流 xff0c 同时也要发布屏幕共享媒体流 下面介绍一种简单的方法
  • Softmax回归模型

    用到的数学概念补充 凸集 xff0c 凸函数 xff0c 黑塞矩阵 简介 节中 xff0c 我们介绍Softmax回归模型 xff0c 该模型是logistic回归模型在多分类问题上的推广 xff0c 在多分类问题中 xff0c 类标签 可
  • Ubuntu记录用户IP访问操作信息工具

    1 用脚本时刻记录用户IP访问操作信息工具 xff0c 用shell脚本去记录 2 每隔一天存放用户信息 xff0c 记录操作时间 xff0c 固定地方存放 脚本如下 在服务器环境变量中加入如下代码 vi etc profile bin b
  • webrtc系列之-像老鼠一样打洞

    众所周知 xff0c 本光头刚涉猎音视频不久 xff0c 所以很多东西都是边学边做的 xff0c 有说得不对的地方 xff0c 请各位多包涵 说穿透之前 xff0c 我们首先需要明白关于WEBRTC的一些概念 xff0c WEBRTC它是一
  • PHP的三种简单实用的传参方式

    首先声明 xff0c 本干货的观点仅代表个人观点 xff0c 拿出来和大家唠叨唠叨 最近在写代码的时候 xff0c 发现了一个有趣的事情 就是我创建了一个新的函数 xff0c 但是因为各种需求 xff0c 各种功能设计的原因 xff0c 函
  • apache rewrite(重定向)

    很多时候 xff0c 由于项目变更的需要 xff0c 我们会将一个网站的域名变更为另外一个域名 xff0c 又或者是一个地址转变为另外一个地址 而在项目里进行跳转并不是一个明智的选择 xff0c 这个时候我们就可以使用到apache的mod
  • 用nginx搭建http透明代理

    背景 代理我们经常听 xff0c 在技术层面我们谈论的代理往往是非透明代理 xff0c 那么既然有非透明代理那就存在有透明代理 我们先看看什么是透明代理 xff0c 引用百度百科的一句话可以描述明白 透明代理的意思是客户端根本不需要知道有代
  • 图片识别之验证码识别

    许多网站在进行某些操作前会要求输入验证码以此来抵御爬虫和攻击 此篇主要讲述如何通过代码来识别一些常见的验证码 以此探究图片识别的过程以及如何避免生成容易被识别的验证码 理论 图片识别的过程 取样本 清洗区分样本 提取样本特征 提取目标的特征
  • CSS(四)——三个盒子的动画效果

    三个盒子的动画效果 span class token selector lt head gt lt meta charset 61 34 UTF 8 34 gt lt meta http equiv 61 34 X UA Compatibl
  • linux C代码调用shell命令方法

    摘抄 xff1a https blog csdn net u010299133 article details 85637263 主要有三种方法 xff1a exec函数簇 xff0c system函数以及popen函数 xff0c 其中需
  • 导出WSL子系统并在服务器Docker上进行部署

    之前一直用的WSL开发 xff0c 后来因为业务需要 xff0c 得迁移到服务器上 xff0c 但是因为安装了很多依赖 xff0c 不想重新装系统 xff0c 所以选择将 WSL子系统打包 xff0c 并用Docker导入 一 WSL导出子
  • Mac OS下关闭本地TimeMachine备份节省磁盘空间

    当我们开启TimeMachine之后 xff0c 在使用外置磁盘时会把备份资料放在外置磁盘上 xff0c 但是某一天发现如下图所示的奇怪现象 xff0c 磁盘使用情况里面竟然有几十GB的 备份 文件 总共256GB容量 xff0c 所以万万
  • 凸函数

    基本介绍 凸函数是一个定义在某个向量空间的凸子集C xff08 区间 xff09 上的实值函数f xff0c 而且对于凸子集C中任意两个向量x1 x2 f x1 43 x2 2 xff08 f x1 43 f x2 2 于是容易得出对于任意
  • Update:Windows Server/Client 各版本信息及更新列表

    1 Windows 11 2 Windows 10 3 Windows nbsp Server 2016 2022
  • [BJWC2010] 严格次小生成树 简单梳理和整理

    https www luogu com cn problem P4180 这篇文章将会默认读者已经掌握了LCA xff0c kruskal等相关基础知识点 考虑最小生成树的 k r u s k