倍增LCA(带修改),codeforce#535F,codeforce#827D

LCA四种写法其一:倍增 文章目录众所周知一、倍增区间倍增二、LCA2.读入数据总结 众所周知 LCA有四种写法 一、倍增 fa[n][logn],fa[i][j]表示i节点的第2^j个父亲。 显然:fa[i][j]=fa[ fa[i][j-1] ][j-1] 即i的第2j个父亲是i的第2(j-1)个父亲的第2(j-1)个父亲。 于是,求i的第k个父亲的复杂度O(k)—>O(logk) 求i的第k个父亲: 1. for(int j=0; j<=log2(k); j++) 2. if((1<<j)&a. 阅读详情

F. MST Unification

https://codeforces.com/contest/1108/problem/F

题意

n个点,m条边,每条边都有一个权值,每次操作可以使得一条边的权值减1,问最小需要几次操作,使得最小生成树唯一。

题解

对于最小生成树不唯一的情况就是,添加一条非树边后(u,v,w)后构成的环中的最小值(除非树边的最小值)等于非树边,这样就可以用非树边去替代这条边使得最小生成树不唯一,所以先构造一棵最小生成树,然后只需要对每条非树边(u,v,w)查询树边u到v中的最小值是否等于w,若等于则需要的操作+1。
这里查找树上(u,v)之间的最小值采用的是倍增LCA的方法。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;

const int maxn = 2e5+5;

int _max[maxn][20];
int dep[maxn];
struct Edge{
    int v,c;
    Edge(int _v,int _c):v(_v),c(_c){}
};
vector<Edge> G[maxn];
int n,m;

void add(int f,int v,int c) {
    G[f].push_back(Edge(v,c));
}
int p[maxn][20];
void dfs(int u,int fa) {
    for(int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i].v;
        if(v == fa) continue;
        _max[v][0] = G[u][i].c;
        dep[v] = dep[u]+1;
        p[v][0] = u;
        dfs(v,u);
    }
}
void initLCA() {
    for(int i = 1; i <= 18; ++i)
        for(int j = 1; j <= n; ++j)  {
            p[j][i] = p[p[j][i-1]][i-1];
            _max[j][i] = max(_max[j][i-1],_max[p[j][i-1]][i-1]);
        }
}
int LCA(int x,int y) {
    if(dep[x] < dep[y])
        swap(x,y);
    int ans = 0;
    for(int i = 18; i >= 0; --i)
        if(dep[p[x][i]] >= dep[y]) {
            ans = max(ans, _max[x][i]);
            x = p[x][i];

        }
    if(x == y)
        return ans;
    for(int i = 18; i >= 0; --i) {
        if(p[x][i] != p[y][i]) {
            ans = max(ans, _max[x][i]);
            ans = max(ans, _max[y][i]);
            x = p[x][i];
            y = p[y][i];
        }
    }
    return max(ans,max(_max[x][0],_max[y][0]));
}
struct Edge2{
    int u,v,w;
    bool operator < (const Edge2& rhs) const {
        return w < rhs.w;
    }
}eg[maxn];
int pre[maxn];
bool flag[maxn];
int find(int x) {
    return x == pre[x] ? x : pre[x] = find(pre[x]);
}
void solve() {
    int cnt = 0;
    for(int i = 0; i < m; ++i)
        if(!flag[i]) {
            int u = eg[i].u, v = eg[i].v;
//            cout << u <<" " << v << " " << LCA(u,v) << endl;
            if(LCA(u,v) == eg[i].w)
                cnt++;
        }
    cout << cnt << endl;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < m; ++i) {
        scanf("%d%d%d", &eg[i].u, &eg[i].v, &eg[i].w);
    }
    for(int i = 0; i <= n; ++i) pre[i] = i;
    sort(eg,eg+m);
    for(int i = 0; i < m; ++i) {
        int uu = find(eg[i].u), vv = find(eg[i].v);
        if(uu != vv) {
            flag[i] = 1;
            add(eg[i].u,eg[i].v,eg[i].w);
            add(eg[i].v,eg[i].u,eg[i].w);
            pre[uu] = vv;
        }
    }
    dep[1] = 1;
    dfs(1,-1);
    initLCA();
    solve();
    return 0;
}

D. Best Edge Weight

https://codeforces.com/problemset/problem/827/D

题意

n个点,m条边,每条边都有一个权值w,问如果这条边在最小生成树上,那么w最大可以是多少?

题解

这和上题差不多,先建一个最小生成树

  1. 对于非树边(u,v)的最大值就是树边上(u,v)的最大值减1。因为对于端点为(u,v)的环,非树边只需要比其中的最大值小1就可以替换一条边。
  2. 对于树边(u’,v’)的最大值就是非树边上(u’,v’)上的最小值减1。如果连上非树边(u’,v’)后构成一个环,那如果这条树边

对于树边上的最大值可以预处理出来,但对于非树边的最小值就需要直接在树上更新。更新的步骤相当于求倍增LCA的逆过程,先按照找LCA的步骤把大区间的最小值更新一下,然后最后再从大的区间更新到小的区间。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 2e5+5;
const int INF = 0x3f3f3f3f;
struct Edge{
    int u,v,w,id;
    Edge(){}
    Edge(int _u, int _v, int _w) :u(_u),v(_v),w(_w){}
    bool operator < (const Edge& rhs) const {
        return w < rhs.w;
    }
};
Edge eg[maxn];
int n,m,pre[maxn],dep[maxn],mx[maxn][20],p[maxn][20], _min[maxn][20];
vector<Edge> G[maxn];
bool flag[maxn];
void add(int u, int v, int w) {
    G[u].push_back(Edge(u,v,w));
}
int find(int x) {
    return x == pre[x] ? x : pre[x] = find(pre[x]);
}
void dfs(int u,int fa) {
    for(int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i].v;
        if(v == fa)
            continue;
        dep[v] = dep[u]+1;
        p[v][0] = u;
        mx[v][0] = G[u][i].w;
        dfs(v,u);
    }
}
void initLCA() {
    for(int i = 1; i <= 18; ++i)
        for(int j = 1; j <= n; ++j) {
            p[j][i] = p[p[j][i-1]][i-1];
            mx[j][i] = max(mx[j][i-1],mx[p[j][i-1]][i-1]);
        }
}
int LCA(int a, int b) {
    if(dep[a] < dep[b])
        swap(a,b);
    int ans = 0;
    for(int i = 18; i >=0; --i) {
        if(dep[p[a][i]] >= dep[b]) {
            ans = max(ans, mx[a][i]);
            a = p[a][i];
        }
    }
    if(a == b) 
        return ans;
    for(int i = 18; i >= 0; --i)
        if(p[a][i] != p[b][i]) {
            ans = max(ans, mx[a][i]);
            ans = max(ans, mx[b][i]);
            a = p[a][i];
            b = p[b][i];
        }
    return max(ans, max(mx[a][0],mx[b][0]));
} 
void update(int x, int y, int val) {
    if(dep[x] < dep[y])
        swap(x,y);
    for(int i = 18; i >= 0; --i) {
        if(dep[p[x][i]] >= dep[y]) {
            _min[x][i] = min(_min[x][i], val);
            x = p[x][i];
        }
    }
    if(x == y)
        return;
    for(int i = 18; i >= 0; --i) {
        if(p[x][i] != p[y][i]) {
            _min[x][i] = min(_min[x][i], val);
            _min[y][i] = min(_min[y][i], val);
            x = p[x][i];
            y = p[y][i];
        }
    }
    _min[x][0] = min(_min[x][0], val);
    _min[y][0] = min(_min[y][0], val);
}
int ans[maxn];
void solve() {
    memset(ans, INF, sizeof ans);  
    memset(_min, INF, sizeof _min);
    for(int i = 0; i < m; ++i) {
        if(!flag[i]) {
            ans[eg[i].id] = LCA(eg[i].u, eg[i].v)-1;
            update(eg[i].u, eg[i].v,eg[i].w-1);
        }
    }
    for(int i = 17; i >= 0; --i)
        for(int j = 1; j <= n; ++j) {
            _min[j][i] = min(_min[j][i],_min[j][i+1]);
            _min[p[j][i]][i] = min(_min[p[j][i]][i], _min[j][i+1]);
        }
    for(int i = 0; i < m; ++i) {
        if(flag[i]) {
            int u = eg[i].u, v = eg[i].v;
            if(p[u][0] == v) {
                ans[eg[i].id] = _min[u][0];
            }
            else 
                ans[eg[i].id] = _min[v][0];
        }
    }
    for(int i = 0; i < m; ++i)
    if(ans[i] == INF) 
        cout << -1 << " ";
    else  
        cout << ans[i] << " ";
    puts("");
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < m; ++i) {
        scanf("%d%d%d", &eg[i].u, &eg[i].v, &eg[i].w);
        eg[i].id = i;
    }
    sort(eg,eg+m);
    for(int i = 0; i <= n; ++i)
        pre[i] = i;
    for(int i = 0; i < m; ++i) {
        int u = eg[i].u, v = eg[i].v;
        int uu = find(u), vv = find(v);
        if(uu!= vv) {
            flag[i] = 1;
            pre[uu] = vv;
            add(u,v,eg[i].w);
            add(v,u,eg[i].w);
        }
    }   
    dep[1] = 1;
    dfs(1,-1);  
    initLCA();
    solve();
    return 0;
}
组合预测模型 | LSTM-XGBoost长短期记忆神经网络结合极限梯度提升树时间序列预测(Matlab程序) 组合预测模型 | LSTM-XGBoost长短期记忆神经网络结合极限梯度提升树时间序列预测(Matlab完整程序) 阅读详情

相关推荐

基于Canfestival的对象字典工具objdictedit.py的运行环境配置

本文以菜狗的视角,一步一步地对对象字典的环境进行配置,旨在能给读者一个比较详细的参考,不恰之处,还请指正。

在线求职中... 3707

倍增LCA

前言 在做树上问题时,我们经常会遇到LCA(最近公共祖先)问题。曾经的我遇到这类问题只会O(n)O(n)O(n)暴力求解,学了倍增LCA,就可以O(logn)O(logn)O(logn)解决了。 ...

CXR的博客 1481

全桥LLC谐振变换器变频控制工作原理与仿真

全桥LLC谐振变换器以其效率高、全范围软开关、器件电应力小等优点,越来越多地应用于大功率场合。电力电子技术的发展日益追求高频化,所带来的问题是半导体开关器件高频运行时的开关损耗急剧增加。各种软开关电路随之出现。可以有效减小开关损耗,使进一步提高开关频率成为可能。谐振式开关因其可在电流自然过零点开通半导体器件,实现零电压开关,特别适合采用MOSFET作开关的装置。最简单的谐振电路有串联谐振(SRC)和并联谐振(PRC)。SRC只能工作于降压状态,应用受限;

晞子的技术札记 3071

DP之倍增算法解决LCA问题

LCA,最近公共祖先,也就是树上两个节点的相同的祖先里距离它们最近的(也就是深度最深的)。倍增算法用于解决LCA问题的在线查询。 比如要找x和y的LCA,一般会怎么做? 首先是暴力。一种是DFS遍历说有点,无需预处理,查询是O(n)的。还有一种暴力是先一步一步将x和y提到同一高度,然后同时看x和y的父节点,相等则是LCA,不等则让x=father(x),y=father(y),这个查询的复杂度...

阿飝的博客 807

告别VBA!用Python+PyWin32自动化你的SolidWorks建模流程(附完整代码)

本文详细介绍了如何利用Python和PyWin32实现SolidWorks建模流程的自动化,替代传统的VBA宏开发。通过环境配置、宏代码转换、高级开发模式及工程化实践等实战内容,帮助机械设计师构建高效、可维护的自动化工作流,显著提升设计效率。

weixin_30485379的博客 365

Serdes之什么是(CDR)?

光收发器和电收发器使用的是我们所说的串行数据通信。在这种通信方式中,数据位是按顺序一个接一个地传输的。光收发器和电收发器使用的是我们所说的串行数据通信。在这种通信方式中,数据位是按顺序一个接一个地传输的。目前市场上大多数收发器都没有专用的时钟输入,因此时钟恢复和数据重新定时等功能是在收发器外部(即在主板上)进行的。接收端则需要恢复时钟以采样串行线上的数据。为了实现这一点,接收端需要一个与输入数据频率大致相同的时钟。通过使参考时钟与输入数据信号的跳变相位对齐,可以生成一个恢复的时钟。这被称为时钟恢复。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 2389

图论算法:树上倍增法解决LCA问题(例题+cpp)

就是把每个 节点的 第 2^j 个的祖先找出来,用于之后的处理,同时我们还需要记录每个节点的。走一条边规定为走了一步,j可以表示为 0 ,1,2 ,分别代表走了 1步,2步,4步。一样,二分是缩小范围的,而倍增是扩大的,因此倍增与二分都具有。可以发现倍增是呈 2的指数型递增的一类数据,和。的时间复杂度,对于求解某些问题是非常高效的。,分别为1:节点6;2:节点5,4:节点1。,我们采用递归的形式,每次递归,走了四步:超过了范围,因此。走了一步: 到达了节点6。走了两步: 到达了节点5。什么是树的公共祖先?

ylh的博客 1766

手把手教你学 NPU 驱动开发--第一部分:基础准备 开发环境搭建:Linux 内核编译与 NPU 仿真平台配置

摘要:本文详细介绍了搭建Linux内核编译与NPU仿真平台的完整流程。主要内容包括:1) 准备ARM64交叉编译工具链;2) 编译支持KGDB调试的Linux内核;3) 构建最小根文件系统;4) 使用QEMU模拟自定义NPU设备;5) 配置KGDB调试环境。文章重点讲解了如何通过修改设备树添加虚拟NPU设备,并提供了开源NPUIP Gemmini作为实验对象。最后展示了简单的"Hello NPU"驱动验证方法,为后续NPU驱动开发奠定了基础。文中还附有常用命令速查表,方便开发者快速搭建调

MHD0815的博客 384

codeforce 1175E Minimal Segment Cover ST表 倍增思想

这题太巧妙了。 题意是,给定2*10^5个区间。然后2*10^5组询问,每次询问一个区间,问至少需要几个给定区间,才能将其完全覆盖。坐标范围5*10^5。 如果只有一个询问区间,是经典的贪心问题。我们每次选择,尽可能覆盖的靠右的区间。 但是这题显然贪心的话,时间是不够的。 考虑使用倍增进行预处理。 我们用dp[i][o]表示从i点开始,选择o个区间,能覆盖到最远哪个点。为-1,...

weixin_30650859的博客 200

基于Verilog的8位CPU设计及UART扩展实现方案,包含完整的架构设计、核心代码实现和仿真验证方法

基于Verilog的8位CPU设计及UART扩展实现方案,包含完整的架构设计、核心代码实现和仿真验证方法

a_zxswer的博客 190

FortiWeb 相对路径遍历漏洞复现(CVE-2025-64446)

FortiWeb是Fortinet公司推出的企业级Web应用防火墙(WAF),专为保护Web应用和API抵御高级威胁设计。它集成人工智能与机器学习技术,通过双层检测引擎(HMM模型与SVM向量机)精准识别异常流量,可防御OWASP Top 10攻击、SQL 注入、XSS、DDoS及恶意机器人。其核心功能包括API自动化保护、虚拟补丁集成(兼容Acunetix等第三方扫描工具)及智能流量分析,支持HTTP/2、WebSocket等现代协议。(CVE-2025-64446)

iSee857的博客 467

codeforce 823 D (倍增LCA)

Descirption Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possibl...

康宇的博客 297

【Embabel Agent】生产级最佳实践与避坑指南

本文围绕架构师最关心的 8 大维度展开:测试策略(FakeOperationContext 实现 Action 级单元测试、Prompt 质量与敏感信息校验)、MCP 集成实战(STDIO/HTTP 双模式、自建 Server、Docker MCP 生态)、RAG 检索增强、OpenTelemetry 全链路可观测性与追踪、Docker/K8s 生产部署、API Key 管理与 @Tool 安全防护、模型选择/缓存/并行等性能优化,以及过度依赖 LLM、忽略错误处理等 8 大常见反模式避坑指南。

program哲学 306

Codeforces 702E 倍增

倍增

stdforces的博客 322

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

CodeForces 1175E Minimal Segment Cover (倍增)

题意:给你n个区间和m次询问,每次询问一个区间[l, r]至少需要几个区间覆盖。 题解:倍增 st[i][j]st[i][j]st[i][j]:从iii出发,走1<<j1<<j1<<j个区间能到达的最远右端点。 先预处理出单个区间中,从某点出发能到达的最远右端点。然后倍增即可。 在判断是否能被区间覆盖时,假设从左端点走最远可不可以到右端点,如果到不了,说明就无法覆盖。 累加答案时是从大到小遍历区间数量,类似不断逼近。 注意区间是从0开始的… #define _CRT_SE

gongyuandaye的博客 347

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Tree CodeForces - 932D 倍增

题目链接:CodeForce-932D 主要思路: 由于操作是加密给出的,我们不得不在线操作。由于又是在树上的结点顺序遍历(一直向其祖先遍历),故可以使用树上的倍增。这里我们定义每一步都是跳到其离他最近的又权值大于他的结点(可以用在倍增表上二分)。在加入节点时,只用知道他下一步的位置,即可继承他走每步的信息。中间再与fa数组一样开一个数组记录跳过的结点的权值之和。查找时逆序枚举2^i步,只要权...

Loging的博客 252

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

codeforces 519E 倍增法LCA

点击打开链接 题意:给一个树,然后每次询问需要统计树上的点到达a和b的最近距离相等,求这样的点的个数 思路:因为是一个树,所以最近距离便是LCA上的边,那么就可以看出来当a和b的距离是奇数时结果为0,当是偶数时,最中间的那个点可以,并且与它相连的不是LCA上的点都是可以的,自己画一个图很好看出来      以前的模版不能快速求出某个点的第几个父亲,而这个可以,以后就用这个,其实记录父节点暴力上

Dan__ge的博客 732

LCA问题(倍增法)

之前写过了LCA的两个在线算法之一:DFS+ST方法(DFS+ST)。本篇介绍另一种在线算法,用倍增思想来解决LCA问题。在学习倍增之前,先看一种倍增算法的退化版,有助于理解倍增法。 在找a和b的LCA时,先让a和b中深度较大的那一个,向上回溯到与另一个同样深度的位置上。例如下面这个图: 假设要找F和E的LCA,先让F向上回溯到他的父节点D的...

Q_M_X_D_D_的博客 1万+

LCA算法-倍增算法

如果你懂二进制,那么你就懂二进制(bushi)

EQUINOX1的博客 2769

NOIP学习笔记——倍增lca

在树或图中,两个点的最近公共祖先,称为这两个点的lca如上图这棵树,根节点是1,要求5和2的lca,不难看出是1;求5和4的lca,不难看出是3。

fhhhcc的博客 1248

LCA算法之倍增

LCA算法之倍增 这里写一篇关于LCA算法倍增的博客。 倍增是LCA暴力之后的优化~ 所以应该比较简单。但是我理解来理解去,理解了一下午??你敢信?? LCA(Least Common Ancestors)最近公共祖先 什么是最近公共祖先?? 就是深度最大的公共祖先 例如下面一棵树 结点3和结点5的最近公共祖先是1; 结点2和结点3的最近公共祖先是4; 结点1和结点4的最近公共祖先是4; 上面说...

qq_44624316的博客 1465

LCA问题——倍增算法,Tarjan算法讲解

LCA问题 前言:助力信息奥赛! 1.LCA &RMQ 首先回想一下RMQ问题:给出一个数组,有多次询问,每次询问一段区间内的最大值。

Lean的博客 3346

算法学习系列(六十二):LCA(最近公共祖先):倍增法、Tarjan算法

关于这个 $LCA$ 问题蓝桥杯这两年考的是也是越来越多了,尤其是去年直接出了个裸题(模板题),也是没想到的,再加上今年省赛 $java$ 组也出了一道与之相关的题,所以今年国赛感觉出的几率也是有的。学下来发现其实也没那么难,又是自己想神秘了,思路和代码总的来说都不是很难,难的是想法,这道题你能否能想到用 $LCA$ 做才是关键,所以本章内容还是采用讲题的策略来进行讲解,就其实都是非常经典的问题,几乎都是模板题,但是我觉得蓝桥杯应该不会出特别难的了,因为本身这个算法就很难,还是要多写写熟即可,继续加油吧!

weixin_60033897的博客 1889

倍增法在线求LCA(详解)

先贴上学习的文章: 洛谷P3379题解1 倍增讲解 在用Tarjan算法求LCA时会出现超时的现象,因为是一层一层的往上跳,于是就有了用倍增法求LCA,是层地往上跳。复杂度:O(nlogn) 1.倍增法思想: 按2的倍数跳,不过是从大到小跳,32,16,8,4,2,1。原因是从小到大跳会出现“悔棋”的现象: 从小到大:5!=1+2+4 从大到小:5=4+1 5<32 (不跳)...

m0_37579232的博客 1978

倍增 LCA(最近公共祖先)

待添

m0_50007959的博客 332

倍增法+LCA(C/C++)

倍增法(C/C++)

m0_71934846的博客 2635
上一篇: Codeforces Round #533 C、D
下一篇: 动态规划 dfs序+LIS
Link_Ray
博客等级 码龄9年 44粉丝 156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值