珂朵莉树(ODT)

珂朵莉树,又叫ODT(Old Driver Tree),所需基础:会用set就行,它是一种基于set的暴力数据结构,常用于区间推平操作中(将一整段区间变成同一个数),来源于Codeforces的某场比赛题。

珂朵莉树的节点

一个珂朵莉树的节点一般维护一个区间的三个值,区间的左端点、右端点以及区间内的值(整个区间的值相同),我们直接用一个struct就行,为了便于后面的操作,我们还需要对小于号重载,因为后面我们要按照区间的左端点排序。

#include<set>
using namespace std;
using LL = long long;
struct node {
	int l, r;
	LL val;
	node(int left, int right = -1, LL v = 0) :l(left), r(right), val(v) {};//构造函数
	bool operator<(const node& no)const {
		return l < no.l;
	}
};
set<node> s;

区间的分割

在使用珂朵莉树时,我们经常会用到分割操作,通常我们的函数会接收一个位置值pos,假设pos在区间l~r之间,那么我们就把这个区间分割为l~pos-1pos~r两部分,并返回pos~r区间的位置,而如果存在区间pos~r的话我们就直接返回该区间的位置。至于这个操作有什么用?后面就知道了。

using IT=set<node>::iterator;
IT split(int pos) {
	IT it = s.lower_bound(node(pos));//找到l大于等于pos的一个区间
	if (it != s.end() && it->l == pos) return it;//如果该区间左端点就是pos,就不用分割了
	--it;//否则it--得到pos所在区间
	int l = it->l, r = it->r;
	LL val = it->val;
	s.erase(it);
	s.insert(node(l, pos - 1, val));
	return s.insert(node(pos, r, val)).first;//set容器insert函数的返回值为pair,第一个元素是插入元素的位置,第二个元素是bool变量表示是否成功插入,如果插入前集合中已经有这个元素了则算做插入失败
}

区间推平

我们前面讲到了split操作,至于它有什么作用,在这里我们将会知晓。区间推平操作也就是把l~r内的值全部修改为val,接下来我们直接看这个函数。

void assign(int l, int r, LL val) {
//注意,这里只能先split(r+1),因为如果先split(l)的话,我们再split(r+1)的时候就可能erase掉itl的位置,然后就RE了
	IT itr = split(r + 1), itl = split(l);//我们把区间分成若干段,并返回左端点为r+1的区间和左端点为l的区间的位置
	s.erase(itl, itr);//删除[itl,itr)之间的所有元素,即删除了区间l~r
	s.insert(node(l, r, val));//插入区间l~r
}

这样我们就完成了珂朵莉树的基本操作。至于如何在题目中使用,还要多加刷题练习。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_bxzzy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值