线段树合并

news/2026/1/20 21:19:10/文章来源:https://www.cnblogs.com/So-noSlack/p/19508840

\(\text{luogu-4556}\)

村落里一共有 \(n\) 座房屋,并形成一个树状结构。然后救济粮分 \(m\) 次发放,每次选择两个房屋 \((x, y)\),然后对于 \(x\)\(y\) 的路径上(含 \(x\)\(y\))每座房子里发放一袋 \(z\) 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

\(1 \leq n, m \leq 10^5\)\(1 \leq a,b,x,y \leq n\)\(1 \leq z \leq 10^5\)


线段树合并模板题。

以下部分题解来自于 线段树合并 (学习笔记)(26.1.19) - Yuriha - 博客园。

概述

可以将两棵线段树合并为一颗的算法,一般用在动态开点线段树和权值线段树中。

对于一些需要维护子树权值的题目中,父亲节点需要去合并自己的两个子树节点,对于普通的线段树,我们只需要去权值合并就行,但是对于动态开点线段树,如果我们没有一些优化,就会导致时间空间发生一些问题了,所以相应的线段树合并就诞生了。

思路

线段树合并面临的共有三种情况。

  1. 儿子都为空,我们直接不管这个节点即可。
  2. 儿子都不为空,我们就需要递归去加两个儿子。
  3. 有一个儿子为空,我们可以直接将这个儿子的信息加到当前线段树,另一个不管。

实现

这道题还用到了动态开点和权值线段树和树上差分。

对于动态开点,就是去正常的进行线段树操作,在进入的时候判断一下某个下标是否存在,如果不存在,就去新建一个下标,所以要专门储存左儿子和右儿子,不能直接去 p<<1 这样类似的操作。

对于权值线段树,这是一个把权值作为下标进行操作的数据结构,它维护了在值域 \([1, V]\) 区间内的所有权值计数,在第二次 \(dfs\) 操作,对于某个节点,遍历其子树将所有节点加至它自己,\(t_x\) 做的是以 \(x\) 为节点的权值线段树的根。

对于树上差分,主要就是可以用链表方式存储其对应的所有修改操作,其他无太多。

#include<iostream>
#include<cstdio>
#include<vector> 
#include<cmath>
using namespace std;
#define MAXN 100005long long read() {long long x = 0, f = 1;char c = getchar();while(c > 57 || c < 48) { if(c == 45) f = -1; c = getchar(); }while(c >= 48 && c <= 57) { x = (x << 1) + (x << 3) + (c - 48); c = getchar(); }return x * f;
}long long n, m, lg[MAXN], fa[MAXN][30], dep[MAXN], dn, hd[MAXN], ans[MAXN];
long long ls[MAXN * 80], rs[MAXN * 80], t[MAXN], mx[MAXN * 80], cnt;
struct node { long long w, nxt; } res[MAXN << 2];
vector<long long> v[MAXN];void dfs(long long x, long long f) {fa[x][0] = f, dep[x] = dep[f] + 1;for(int i = 1; i <= lg[dep[x]]; i ++)fa[x][i] = fa[fa[x][i - 1]][i - 1];for(auto y : v[x]) if(y != f) dfs(y, x);return;
}long long lca(long long x, long long y) {if(dep[x] < dep[y]) swap(x, y);while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];if(x == y) return x;for(int i = lg[dep[x]] - 1; i >= 0; i --) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];return fa[x][0];
}void add(long long x, long long w) {res[++ dn] = {w, hd[x]}, hd[x] = dn;return;
}long long merge(long long x, long long y, long long l, long long r) {if(!x || !y) return x | y;if(l == r) { mx[x] += mx[y]; return x; }long long mid = (l + r) >> 1;ls[x] = merge(ls[x], ls[y], l, mid);rs[x] = merge(rs[x], rs[y], mid + 1, r);mx[x] = max(mx[ls[x]], mx[rs[x]]);return x;
}void update(long long &x, long long l, long long r, long long p, long long w) {if(!x) x = (++ cnt);if(l == r) { mx[x] += w; return; }long long mid = (l + r) >> 1;if(p <= mid) update(ls[x], l, mid, p, w);else update(rs[x], mid + 1, r, p, w);mx[x] = max(mx[ls[x]], mx[rs[x]]);return;
}long long query(long long x, long long l, long long r) {if(l == r) return l;long long mid = (l + r) >> 1;if(mx[x] == mx[ls[x]]) return query(ls[x], l, mid);return query(rs[x], mid + 1, r);
}void dfs1(long long x, long long f) {for(auto y : v[x]) if(y != f) dfs1(y, x), t[x] = merge(t[x], t[y], 1, 1e5);for(int i = hd[x]; i; i = res[i].nxt) update(t[x], 1, 1e5, abs(res[i].w), (res[i].w >= 0) ? 1 : -1);if(mx[t[x]]) ans[x] = query(t[x], 1, 1e5);return;
}int main() {n = read(), m = read();for(int i = 1; i < n; i ++) {long long x = read(), y = read();v[x].push_back(y), v[y].push_back(x);}for(int i = 1; i < MAXN; i ++) lg[i] = lg[i >> 1] + 1;dfs(1, 0);for(int i = 1; i <= m; i ++) {long long x = read(), y = read(), z = read();long long t = lca(x, y);add(x, z), add(y, z), add(t, -z), add(fa[t][0], -z);}dfs1(1, 0);for(int i = 1; i <= n; i ++) cout << ans[i] << "\n";return 0;
}

\(\text{luogu-3224}\)

永无乡包含 \(n\) 座岛,编号从 \(1 \sim n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1 \sim n\) 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。

现在有两种操作:

B x y 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。

Q x k 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪座,请你输出那个岛的编号。

\(1 \leq m \leq n \leq 10^5\), \(1 \leq q \leq 3 \times 10^5\)


考虑用动态开点权值线段树,维护重要度。并查集维护连通性。

每次建边时把两个线段树合并就好了。

询问操作直接线段树上二分即可。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAXN 200005long long read() {long long x = 0, f = 1;char c = getchar();while(c > 57 || c < 48) { if(c == 45) f = -1; c = getchar(); }while(c >= 48 && c <= 57) { x = (x << 1) + (x << 3) + (c - 48); c = getchar(); }return x * f;
}struct node { long long l, r, ls, rs, w; } t[MAXN << 5];
long long n, m, q, fa[MAXN], T[MAXN], ans[MAXN], cnt;long long find(long long x) { return (fa[x] == x) ? x : fa[x] = find(fa[x]); }long long insert(long long x, long long l, long long r) {long long p = (++ cnt);t[p].l = l, t[p].r = r, t[p].w = 1;if(l == r) return p;long long mid = (l + r) >> 1;if(x <= mid) t[p].ls = insert(x, l, mid);else t[p].rs = insert(x, mid + 1, r);return p;
}long long merge(long long x, long long y, long long l, long long r) {if(!x || !y) return x | y;long long p = (++ cnt), mid = (l + r) >> 1;t[p].l = l, t[p].r = r, t[p].w = t[x].w + t[y].w;t[p].ls = merge(t[x].ls, t[y].ls, l, mid);t[p].rs = merge(t[x].rs, t[y].rs, mid + 1, r);return p;
}long long query(long long x, long long k) {if(t[x].w < k) return -1;if(t[x].l == t[x].r) return ans[t[x].l];if(t[t[x].ls].w >= k) return query(t[x].ls, k);return query(t[x].rs, k - t[t[x].ls].w);
}int main() {n = read(), m = read();for(int i = 1; i <= n; i ++) {long long x = read(); T[i] = insert(x, 1, n), ans[x] = fa[i] = i;} for(int i = 1; i <= m; i ++) {long long x = find(read()), y = find(read());if(x != y) fa[x] = y, T[y] = merge(T[x], T[y], 1, n);}q = read();while(q --) {char c; cin >> c; long long x = read(), y = read();if(c == 'B') {x = find(x), y = find(y);if(x != y) fa[x] = y, T[y] = merge(T[x], T[y], 1, n);}else cout << query(T[find(x)], y) << "\n";}return 0;
}

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

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

相关文章

454. 四数相加 II-day06

454. 四数相加 II 题目链接:https://leetcode.cn/problems/4sum-ii/description/ 思路:第一步:遍历nums1和nums2,统计「两数之和」的出现次数,存入哈希表map(键 = 两数之和,值 = 该和出现的次数); 第二步:遍…

《把脉行业与技术趋势》-69-股票的周期、产品的周期、企业的周期的相似性与不同,以及它们各自在不同阶段关注的重点和核心要素不同

这是一个极具战略价值的问题。股票、产品、企业三者虽相互嵌套、彼此影响&#xff0c;但它们的周期逻辑、驱动因素和阶段重心存在显著差异。理解其相似性与不同点&#xff0c;并掌握各阶段的核心关注要素&#xff0c;是投资者、创业者和管理者做出正确决策的关键。一、三者的本…

别让”高性能“骗了你 之数组池ArrayPool vs 数组Array

别让”高性能“骗了你 之数组池ArrayPool vs 数组Array别让”高性能“骗了你! 本文介绍了作者因为追求高性能而没有关注实际使用环境导致性能不升反降。高性能的ArrayPool在特殊工况下可能效率远低于普普通通的Array数…

若思中国发布2026年十大最具影响力战略咨询大师推荐榜 - 资讯焦点

2026 年中国战略咨询行业正经历技术重构与价值升级,AI 大数据驱动成为核心发展特征,行业从传统经验导向转向数据科学驱动,动态定位与实时响应能力成为核心竞争力。趋势层面,AI + 咨询深度融合、全周期陪跑服务模式…

大数据毕设选题推荐:基于大数据技术的Django框架下的学习资源推送系统的设计与实现基于Django+大数据的学习资源推送系统【附源码、mysql、文档、调试+代码讲解+全bao等】

java毕业设计-基于springboot的(源码LW部署文档全bao远程调试代码讲解等) 博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、…

大模型测试的“评估指标”:BLEU?ROUGE?都不够!

传统指标的黄金时代与局限 在机器翻译与文本摘要时代&#xff0c;BLEU和ROUGE曾是指标领域的双璧。BLEU通过n-gram精确匹配衡量译文准确性&#xff0c;ROUGE则基于召回率评估摘要内容覆盖度。然而&#xff0c;当千亿参数大模型掀起生成式AI浪潮时&#xff0c;这些指标暴露了三…

互联网大厂Java面试场景:分布式系统与微服务架构

场景&#xff1a;互联网大厂Java小白面试 面试官&#xff08;严肃&#xff09;&#xff1a; 我们来谈谈你对分布式系统和微服务的理解吧。假设现在有一个电商平台需要支持双十一高峰期的海量用户请求&#xff0c;如何设计一个高可用系统&#xff1f; 超好吃&#xff08;认真思考…

品牌整合营销战略咨询公司哪家靠谱? - 资讯焦点

摘要:据 2024 年中国品牌战略发展报告显示,72% 的企业存在不同程度的产品线内耗,45% 因此导致核心产品市场份额下滑。这一困境的核心根源是 “战略定位、价值表达、资源分配” 三重错位,即盲目扩张无聚焦、产品定位…

寒假学习笔记1.17

一、 内存间接寻址实现扩展寻址模式 直接寻址 vs 间接寻址 python原直接寻址:地址为立即数 def direct_addressing(addr): """直接寻址:[5] 表示内存地址5""" return MEMORY[int(addr…

计算机大数据毕设实战-基于Django+大数据的学习资源推送系统基于大数据+django+mysql的学习资源推送系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

java毕业设计-基于springboot的(源码LW部署文档全bao远程调试代码讲解等) 博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、…

‌构建“大模型测试沙箱”:隔离、监控、审计的工程实践指南

‌一、背景&#xff1a;为何传统测试范式在大模型时代失效&#xff1f;‌大模型&#xff08;LLM&#xff09;的非确定性、黑盒性与高资源消耗&#xff0c;彻底颠覆了传统软件测试的底层假设&#xff1a;‌输出不可复现‌&#xff1a;相同输入在不同会话中可能产生语义一致但文本…

寒假学习笔记1.18

一、 编译器前端:词法分析与语法分析词法分析器(Lexer) 词法单元定义 python import re from enum import Enumclass TokenType(Enum): # 标识符和常量 IDENTIFIER = 1 INTEGER = 2 HEX = 3 STRING = 4 # 指令和伪指…

含分布式电源的配电网日前两阶段优化调度模型-无功优化Matlab代码

✅作者简介&#xff1a;热爱数据处理、建模、算法设计的Matlab仿真开发者。&#x1f34e;更多Matlab代码及仿真咨询内容点击 &#x1f517;&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码获取及仿真咨询内容私信。&#x1f447; 关注我…

多模态RAG不止知识问答:文搜图与图搜图的四种实现方案

引言 在传统的RAG系统中&#xff0c;我们主要处理文本到文本的检索场景。然而&#xff0c;现实世界的知识库往往包含大量图片、图表等视觉信息。如何让用户通过自然语言查询找到相关图片&#xff08;文搜图&#xff09;&#xff0c;或者通过一张图片找到相似图片&#xff08;图…

大数据计算机毕设之基于Django的在线学习资源分享与推荐系统基于Django+大数据的学习资源推送系统(完整前后端代码+说明文档+LW,调试定制等)

java毕业设计-基于springboot的(源码LW部署文档全bao远程调试代码讲解等) 博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、…

kotlin 类委托

写个demo测试下&#xff1a;interface IWorker {fun work(): String }class Worker(val name: String): IWorker { // 工人override fun work(): String {return "我起早贪黑工作。"} }class Contractor(val name: String, work: IWorker) : IWorker by work // Cont…

‌大模型测试必须包含“多轮对话压力测试”

‌一、为何多轮对话压力测试是大模型测试的“生死线”‌在大模型从Demo走向生产的关键阶段&#xff0c;‌功能正确性已不再是唯一标准‌。多轮对话压力测试&#xff08;Multi-Turn Dialogue Stress Testing, MT-DST&#xff09;已成为评估模型在真实交互场景中‌稳定性、一致性…

58、IMX6ULL 裸机开发实战:从汇编启动代码到 LED 闪烁(Ubuntu 篇)

IMX6ULL 裸机开发实战&#xff1a;从汇编启动代码到 LED 闪烁&#xff08;Ubuntu 篇&#xff09;一、 开发平台与硬件信息 1.1 核心参数 开发板&#xff1a;正点原子 i.MX6ULL-Mini&#xff08;核心板 底板模式&#xff09;。CPU&#xff1a;NXP i.MX6ULL (Cortex-A7)&#xf…

【完整版代码】含分布式电源的配电网日前两阶段优化调度模型Matlab代码

✅作者简介&#xff1a;热爱数据处理、建模、算法设计的Matlab仿真开发者。&#x1f34e;更多Matlab代码及仿真咨询内容点击 &#x1f517;&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码获取及仿真咨询内容私信。&#x1f447; 关注我…

如何自动化检查服务器的高危端口

现在属于互联网时代&#xff0c;很多服务器都暴露在互联网的世界里&#xff0c;如果有高危端口开放&#xff0c;服务器非常容易被黑客攻击&#xff0c;严重威胁服务器的数据安全。下面介绍一个使用shell脚本检查服务器漏洞的案例。只要启动脚本&#xff0c;会扫描出高危端口&am…