基于STL库set容器实现的珂朵莉树

基于CutLSTM-ATT 模型的刀具磨损预测-【一个月之内发一篇中文核心辅导】 阅读详情

基于STL库set容器实现的珂朵莉树

简介

珂朵莉树,起源于codeforce896C,是一种将值相同的区间合并在同一节点的从而进行操作的算法。

例: 序列 a n : 1 、 1 、 1 、 1 、 2 、 3 、 3 、 4 、 5 、 5 、 6 、 6 a_n:1、1、1、1、2、3、3、4、5、5、6、6 an​:1、1、1、1、2、3、3、4、5、5、6、6可以被表示为下图
在这里插入图片描述

每数个相同的数据项都被转化为了一段区间存储在同一节点中。

用处

拿样例分,只要不遇见特意设置的数据,保证数据为随机生成的,基于set实现的珂朵莉树上的相关操作都能做到 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)级别的复杂度,详细证明可看珂朵莉树的复杂度分析 - 知乎 。

俗话说的好,遇见动规用贪心,区间问题珂朵莉,只要出题人没有刻意为难,都可以通过部分测试用例,妥妥的拿分神器,蓝桥杯必备。

*ps:*如果想正经解决区间问题,还是把线段树学好。

构建方法

创建节点

#include<iostream>
#include<set>

using namespace std;

struct node//构建节点
{
	int _left, _right;//存储左右边界
	mutable int _val;//使用mutable关键字标注_val值可更改
	node(int L = 0, int R = -1, int V = 0) :_left(L), _right(R), _val(V) {}//构造函数,为节点默认赋值
	bool operator < (const node& x) const //重载<运算符,使节点在set容器存储时使用左边界进行比较,维护区间
	{
		return _left < x._left;
	}
};

set<node>s;//使用set容器来对珂朵莉树进行存储和维护
set容器简介

set 是使用红黑树来实现的一种关联式容器。平衡二叉树的特性使得 set 非常适合处理需要同时兼顾查找、插入与删除的情况。

和数学中的集合相似,set 中不会出现值相同的元素。

插入与删除操作
  • insert(x) 当容器中没有等价元素的时候,将元素 x 插入到 set 中。
  • erase(x) 删除值为 x 的 所有 元素,返回删除元素的个数。
  • erase(pos) 删除迭代器为 pos 的元素,要求迭代器必须合法。
  • erase(first,last) 删除迭代器在 (first,last)范围内的所有元素。
  • clear() 清空 set。
迭代器

(可以粗略的认为是指针)

set 提供了以下几种迭代器:

  1. begin()/cbegin()
    返回指向首元素的迭代器,其中 *begin = front。
  2. end()/cend()
    返回指向数组尾端占位符的迭代器,注意是没有元素的。
  3. rbegin()/crbegin()
    返回指向逆向数组的首元素的逆向迭代器,可以理解为正向容器的末元素。
  4. rend()/crend()
    返回指向逆向数组末元素后一位置的迭代器,对应容器首的前一个位置,没有元素。

以上列出的迭代器中,含有字符 c 的为只读迭代器,你不能通过只读迭代器去修改 set 中的元素的值。如果一个 set 本身就是只读的,那么它的一般迭代器和只读迭代器完全等价。只读迭代器自 C++11 开始支持。

查找操作
  • count(x) 返回 set 内键为 x 的元素数量。
  • find(x) 在 set 内存在键为 x 的元素时会返回该元素的迭代器,否则返回 end()。
  • lower_bound(x) 返回指向首个不小于给定键的元素的迭代器。如果不存在这样的元素,返回 end()。
  • upper_bound(x) 返回指向首个大于给定键的元素的迭代器。如果不存在这样的元素,返回 end()。
  • empty() 返回容器是否为空。
  • size() 返回容器内元素个数。

分割操作

作为珂朵莉树中的核心操作,其他操作离不开分割操作。

例如:分割位置7。位置7在节点在这里插入图片描述
的区间之中,将该位置分割分割,节点
就被分割为了在这里插入图片描述

序列 a n : 1 、 1 、 1 、 1 、 2 、 3 、 3 、 4 、 5 、 5 、 6 、 6 a_n:1、1、1、1、2、3、3、4、5、5、6、6 an​:1、1、1、1、2、3、3、4、5、5、6、6

分割前:在这里插入图片描述

分割后:在这里插入图片描述

auto split(int pos)
{
	auto it = s.lower_bound(node(pos));//使用lower_bound寻找蕴含目标位置的节点的下一个节点,并创建一个迭代器it来存储这个节点
    //注:由于我们在node中重载了<操作符,所以查找的目标是拥有最小大于等于目标值的左边界的节点,例如目标值是7定位到的就左边界为8的节点
    //注:如果迭代器指向end(),说明当前容器中不存在目标位置
	if (it != s.end() && it->_left == pos)//如果迭代器指向的节点的左边界与目标位值相同,例如pos=6时,说明这个位置已经被分割,直接返回当前迭代器就行
		return it;//返回迭代器方便后续操作
	it--;//如果目标位置未被分割,将迭代器前推,拿到包含目标位置的节点
	int l = it->_left;//使用l存储左边界
	int r = it->_right;//使用r存储右边节
	int v = it->_val;//使用v存储节点的值

	s.erase(it);//先将含有目标位置的节点删除
    //再将两个拆分好的节点插入
	s.insert(node(l, pos - 1, v));//使用预先存好的l作为左边界,pos-1作为右边界,v为节点值存入set中,分割原节点后的前半部分节点就存入了
	return s.insert(node(pos, r, v)).first;//后半部分同理,使用pos作为左边界,r作为右边界,v为节点值存入set中,并使用.first返回分割原节点后的后半部节点的迭代器
}

推平操作

作为珂朵莉树中的核心操作,可以把将指定区间中的所有值更改。

void tp(int l, int r, int v)
{
	auto itR = split(r + 1);//将指定右边界先进行分割,并使用迭代器itR存储分割后的后半节点,即非目标区间的第一个节点
    //注:一定要先切割右边界,再切割左边界,否则如果遇见左边界在第一个节点且右边界也在第一个节点的情况,先切割左节点将导致迭代器指向错误
	auto itL = split(l);//将指定的左边界进行切割,并使用迭代器itL存储分割后的后半部分,即目标区间的第一个节点
    
	s.erase(itL, itR);//先将左右边界之间的所有节点删除
	s.insert(node(l, r, v));//然后把指定值的节点插入,该节点的左边界就是l,右边界就是r,值为v。
}

指定区间的遍历

基本上其他对于区间的操作都是基于指定区间的遍历完成的

void ergodic(int l, int r)
{
	auto itR = split(r + 1);//切割右边界
	auto itL = split(l);//切割左边界

	for (auto it = itL; it != itR; ++it)//创建迭代器it指向目标区间中的第一个节点,不断对迭代器迭代,直到指向非目标区间的第一个节点
	{
        fun();//将要实现的功能
	}
}

基于指定区间的遍历完成的操作

指定区间求和

求目标区间所有值之和

int ask(int l, int r)
{
	int ans = 0;//注:计算区间和的时候要注意数据范围,一般都会使用long long来存储答案
	auto itR = split(r + 1);
	auto itL = split(l);

	for (auto it = itL; it != itR; ++it)
	{
		ans += (it->_right - it->_left + 1) * it->_val;//计算区间长度并乘以区间的值,添加到答案中
	}
	return ans;
}
指定区间加值

给指定区间的节点加上指定值

void add(int l, int r,int v)
{
	auto itR = split(r + 1);
	auto itL = split(l);

	for (auto it = itL; it != itR; ++it)
	{
        it->_val += v;
	}
}
指定区间的交换

交换两个区间

//开两个节点数组a和b用来存储节点,方便交换时使用,就像我们最开始写交换函数一样,使用一个中继器来存储需要交换的数据
node a[N];
node b[N];

void swapInterval(int l1, int r1, int l2, int r2)
{
	if (l1 > l2)//判断l1是否大于l2,大于则交换一下,防止切割顺序出错,我在卡了三四个小时,血的教训
	{
		swap(l1, l2); 
		swap(r1, r2);
	}
	int len1 = 0, len2 = 0;//使用len1和len2来存储目标区间1和目标区间2的节点数
    
	auto itR1 = split(r1 + 1);
	auto itL1 = split(l1);
    
	for (auto it = itL1; it != itR1; ++it)//遍历区间1将节点存入数组a中
	{
		a[++len1]._left = it->_left;
		a[len1]._right = it->_right;
		a[len1]._val = it->_val;
	}

	auto itR2 = split(r2 + 1);
	auto itL2 = split(l2);
    
	for (auto it = itL2; it != itR2; ++it)//遍历区间2将节点存入数组b中
	{
		b[++len2]._left = it->_left;
		b[len2]._right = it->_right;
		b[len2]._val = it->_val;
	}

	itR1 = split(r1 + 1);//由于迭代器被迭代了,所以需要归位一下,又是几个小时,说多了都是泪
	itL1 = split(l1);
    
	s.erase(itL1, itR1);//删除区间1

	itR2 = split(r2 + 1);
	itL2 = split(l2);
    
	s.erase(itL2, itR2);

	for (int i = 1; i <= len2; ++i)//遍历数组b,将数组中的节点依次插入区间1中
	{
		s.insert(node(b[i]._left - l2 + l1, b[i]._right - l2 + l1, b[i]._val));//原边界加上区间1和区间2的边界差就是交换后的边界位置。
	}
    
	for (int i = 1; i <= len1; ++i)
	{
		s.insert(node(a[i]._left - l1 + l2, a[i]._right - l1 + l2, a[i]._val));
	}

}

练习题

  1. Physical Education Lessons - 洛谷
  2. P4979 矿洞:坍塌 - 洛谷
  3. P5350 序列 - 洛谷 写了我七八个小时的题目,说多了都是泪
2026年寒武纪数字IC笔试试卷带答案 本文摘要: 该数字IC设计测试卷包含单选题(30分)、波形分析题(15分)、多选题(30分)三类客观题,覆盖时序约束、半导体工艺、状态机、数制转换、同步复位等核心知识点。重点考察:1)跨时钟域处理(如异步FIFO、格雷码应用);2)时序分析(建立/保持时间、时钟约束指令);3)低功耗设计技术(时钟门控、DVFS);4)寒武纪MLU架构特性(张量核、混合精度计算)。解析强调工程实践要点,如异步复位需同步释放、建立时间违例与频率的关联性等。试题难度梯度明显,既包含基础概念辨析(如Moore/Mealy状态机), 阅读详情

相关推荐

Kubernetes集群资源优化实战:Volcano调度器如何帮你省下30%GPU算力

本文详细介绍了如何通过Volcano调度器的Binpack策略优化Kubernetes集群中的GPU资源利用率,解决AI模型训练中的资源碎片化问题。通过实战配置和调优指南,帮助用户提升30%的GPU算力利用率,显著降低任务等待时间和硬件成本。

weixin_30832143的博客 507

珂朵莉树(ODT)

珂朵莉树 ODT 主要内容 珂朵莉树是基于数据随机且有整体赋值操作而对序列操作的乱搞算法。 它的主要思想是用 set 维护若干个数值上相同的区间,并暴力处理其他询问。 建立 在 set 中,我们需要用结构体记录每个区间的信息: struct NODE { int l,r; mutable ll val; // mutable 表示可变的,便于在外边修改 val 的值 NODE(int...

EricQian的博客 3044

CentOS7下Node.js v20+安装与常见依赖库问题解决指南

本文详细介绍了在CentOS7系统下安装Node.js v20+的完整流程及常见依赖库问题的解决方案。通过升级glibc到2.28+、配置环境变量以及处理libstdc++版本问题,帮助开发者顺利在老旧系统上部署最新版Node.js,提升开发效率。

weixin_30689307的博客 157

【算法】【C++、珂朵莉树】珂朵莉树,以力扣715. Range 模块为例

对小于运算符的重载,保证了节点在set中的有序性在声明变量val,也就是区间的值的时候,也要声明mutable,否则可能会CE,因为要进行区间赋值操作。int le, ri;本文详细介绍了如何使用珂朵莉树解决力扣715号问题,包括数据结构的设计思路和每个方法的实现步骤。通过合理的数据结构选择和高效的区间操作,我们实现了一个能够有效跟踪数字范围的Range模块。

未来就在脚下。 1509

YOLOv8进阶:SEAM注意力与Repulsion Loss双剑合璧,突破遮挡检测瓶颈

做目标检测时,最头疼的莫过于目标被遮挡的场景——行人被树木挡住一半、车辆被广告牌遮挡部分轮廓……这些情况往往让模型“犯迷糊”。但现在,有了SEAM注意力模块和Repulsion Loss排斥损失,我们就能让YOLOv8在遮挡场景下也能“拨开迷雾见真章”。这篇教程会带你一步步理解这两个技术,并亲手把它们融入YOLOv8,让你的检测模型在复杂场景下也能稳如泰山。

FJN110的博客 233

后仿真中《SDF反标必懂连载篇》之 Negative Delay (理论篇)

今天,学习一下SDF文件中的负数延时问题。比如下面的图片中的SETUPHOLD 中的hold time 为负数。

那么菜的博客 2577

珂朵莉树(ODT)

珂朵莉树

csdnwqy030429的博客 1111

Python数据可视化 Pyecharts 制作 Map 地图

大家好,我是Mr数据杨。想象一下,作为一名军师,如诸葛亮或郭嘉,'Map’就如同那战争的沙盘,兵马行动的轨迹,都需要准确的地图作为基础。‘基本设置’,就如同摆设这张战争沙盘,规定棋子的起始位置。‘数据配置选项’和’地图数据项’,就好比是军师们手中的情报,了解各路诸侯的兵力、粮草、地形等重要信息,以便于他们更好地布局。‘Demo’则代表着练兵之地,军师们可以在此基于已有数据,试验各种战术。

Mr数据杨 4万+

[数据结构]珂朵莉树

前言 关于珂朵莉  珂朵莉是世界上最幸福的女孩子,没有之一,不接受任何反驳 \(\ \ \ \ \text{最幸福最幸福最最最幸福}\dots\text{的女孩子哦!}\)          上图左珂朵莉·诺塔·瑟里欧尼斯,右威廉·克梅修 关于这个数据结构的名字 为了CF896C发明了这个算法,而这道题题面又与珂朵莉有关,故称为珂朵莉树,由于发明者的原因,也珂叫ODT(Old Driver Tre...

weixin_30481087的博客 483

Loop Engineering 来了:从写 Prompt 到设计 Loop,AI 编程的第四次范式跃迁

文章摘要: Loop Engineering是AI编程领域的新范式,标志着从"人手动喂指令"到"设计自驱动循环"的跃迁。其核心在于通过五个组件(定时器、工作空间、知识体系、连接器和子Agent验证)构建自动化任务流,使AI系统能自主运行。这一概念的火爆源于模型能力和工具链的成熟,使得任务设计成为关键瓶颈。作者指出,从Prompt到Loop的四次范式跃迁(语言学→信息科学→控制论→管理学)反映了人机协作关系的根本变化:人类角色从执行者逐渐退居为目标设定者。落地Loop Engineering的真正挑战在于目标

少说,多做 330

CCF编程培训师资认证(PTA)标准(教学能力T)

随着计算机科学的不断发展,计算机相关技术应用到社会各个行业,越来越多的青少年参加到了计算机程序设计的学习中,这对编程培训教师提出了更高的专业要求和职业要求。CCF开展编程培训师资认证项目(Programming Trainer Accreditation,PTA),旨在建立一个规范的、科学的、权威且有公信力的三方认证。认证考试分编程专业能力(P)和教学能力(T)两部分。本标准根据《CCF编程培训师资认证条例》第十条制定,旨在明确教学能力(T)的测试标准。

lan_in的博客 1712

浅谈珂朵莉树(Chtholly Tree)——暴力而玄学的数据结构

关于它很珂学的名字… 珂朵莉树(Chtholly Tree),又称老司机树(Old Driver Tree),起源于CodeFoeces平台上编号为896C的一道题—— “ Willem, Chtholly and Seniorious ” (珂学家们此时不用翻译也知道这个名字是在说啥了) ,一位用户Old Driver在给出了线段树的正解之后,又发布了YY多年的 一份前所未有的玄学解法,其中利用......

CC_dsm的博客 2万+

SAP MM模块后续借记、后续贷记、贷方凭证简介

在SAP系统中,后续借记、后续贷记和贷方凭证是处理供应商发票、采购和付款过程中常见的财务交易。

我小时候很黑的博客 3270

洛谷 2787 珂朵莉树(ODT)

数据被加强了,(ODT)(ODT)(ODT)无法水过这个题了,但我还是要写一写这个新学习的黑科技算法。 这个算法,和spfaspfaspfa一样很香,但唯一不同点是,spfaspfaspfa众所周知,而珂朵莉树(ODT)(ODT)(ODT)鲜为人知,他们过随机数据都十分快。 (ODT)(ODT)(ODT)是基于stlstlstl里面的setsetset来实现的,通过一个平推操作,使复杂度快速下降,平推操作可以使setsetset容器中的数量快速下降,从而做到近似O(n)O(n)O(n)的时间复杂度,在空间上

yangzijiangac的博客 781

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

珂朵莉树(ODT)(玄学)

这玩意我觉得是KDT的亲戚。 但是这玩意比KDT好卡多了。 主要思想就是把[1,n][1,n][1,n]的区间划分为多个[1,r1],[r1+1,r2]....[1,r_1],[r_1+1,r_2]....[1,r1​],[r1​+1,r2​]....的区间且每个区间内,所有点的信息相等。 用std::setstd::setstd::set维护。 感觉属于熟练掌握STL的范畴。 如果数据随机而且有...

Freopen的博客 612

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

珂朵莉树学习

【代码】珂朵莉树学习。

小刀刺大熊 140

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

ODT珂朵莉树

珂朵莉树の由来 珂朵莉树(或称ODT(Old Driver Tree老司机树)) 这毒瘤算法由CodeForces - 896C Willem, Chtholly and Seniorious 的正解衍化而来 由于其骗分暴力的非正统算法思想 虽然很多时候在随机数据下跑时不错 但切记这只是骗分暴力,时间复杂度上并不正确 什么时候用珂朵莉树 珂朵莉树一般用来解决本来应当由线段树解决的区间类问题 而使...

niiick 5496

【算法】珂朵莉树板子

https://www.luogu.com.cn/problem/CF896C<---例子 #include<bits/stdc++.h> using namespace std; #define SET0(a) memset(a,0,sizeof(a)) #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define DWN(i,a,b) for(int i=(a);i>=(b);i--) typedef long long ..

melon_sama的博客 295

Chtholly Tree (珂朵莉树) ODT

ODT,OldDriverTree,又名ChthollyTreeODT,OldDriverTree,又名ChthollyTreeODT ,Old Driver Tree,又名 Chtholly Tree −关键操作推平一段区间−关键操作推平一段区间 - 关键操作 推平一段区间 1. CF 896C Willem, Chtholly and Seniorious #include...

Bryce1010's Blog 4520

深挖C++:类和对象(中)

(先进后出)

xys_678的博客 249

C++移动构造函数详解

移动构造函数是C++11引入的一种特殊构造函数,用于从临时对象(右值)"窃取"资源来初始化新对象,而不是进行昂贵的深拷贝。char* data;public:// 移动构造函数:参数是右值引用 &&// 关键:把源对象的资源置空。

拒绝AI文,努力在AI时代写出感动人心的好文章 393

ThunderKittens 深度解析:一个不基于 MLIR 的 C++ 模板 GPU DSL

Triton 是"让更多人能写 GPU kernel",ThunderKittens 是"让会写的人写得更爽"。前者用 MLIR 换易用性,后者用 C++ 模板换可控性。它们不是替代关系,而是覆盖了 GPU 编程光谱的两端。ThunderKittens 的出现,本质上是对"GPU DSL 必须基于 MLIR"这一默认假设的挑战。编译期类型系统本身就可以是一个强大的 DSL 基础设施,不需要中间 IR,不需要黑盒 pass,也能实现 tile 级抽象和零运行时开销。

Maxwell_Newton的博客 345

跟我学c++中级篇—类型定义的方式

本文系统阐述了编程中类型定义的重要性及c++中的实现方式。重点对比了宏定义、typedef与modern using三种机制,指出using在可读性、灵活性和模板支持上的优势,推荐优先使用。同时提醒开发者注意别名滥用、类型歧义、错误信息冗长等问题,强调统一规范与合理设计。最终结论:在现代c++开发中,应以using为主,兼顾简洁性与可维护性,避免陷入命名混乱与编译困境。

fpcc的专栏 85

【C语言】字符与字符串函数

C语言中字符串为以\0结尾的字符数组,标准库函数基于此约定。本文解析字符串内存布局,详解ctype.h与string.h中字符分类、长度计算、拷贝、比较等函数的使用要点,强调长度判断与越界风险,最后通过命令行待办事项示例整合fgets、sscanf、strncpy、strcmp,展示实际应用中的关键细节。

记录在学习过程中学到的知识 354

C++ 函数模版

模板参数:● template ,T 就是类型占位符,名字可以自定义,习惯用T● 占位符可以在函数返回值、形参、函数内部当作类型使用使用要点模板代码一般写在头文件:编译器需要看到完整模板源码,才能在每个编译单元完成实例化全局函数、类内成员函数都可以写成模板实例化发生在编译阶段,不是运行时隐式实例化:调用时编译器自动推导实参类型,生成对应版本函数。

2501_94041724的博客 306

C++ 运行时多态与虚函数机制全面剖析【面试重点】

构成C++ 运行时多态必须是基类的指针或者引用调用虚函数。被调用的函数必须是虚函数,并且派生类必须对该虚函数完成重写/覆盖(Override)。只有基类的指针或引用才能既指向基类对象,又指向派生类对象(切片机制);而只有完成了虚函数重写,派生类与基类才具备不同的函数行为,达到“指向谁就调用谁”的效果。在类成员函数的前面加上virtual关键字修饰,该成员函数就成为了虚函数。public:// 成员函数前加 virtual 修饰,声明为虚函数。

Fuyo_0209的博客 445
上一篇: ICPC网络预选赛第二场个人题解
下一篇: 线段树的构建
ExtractStars
博客等级 码龄4年 1053粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值