首页 > 其他分享 >[学习笔记]珂朵莉树

[学习笔记]珂朵莉树

时间:2023-12-18 23:46:24浏览次数:28  
标签:Node 学习 return val Chtholly int 笔记 朵莉树 split

目录
0x00:介绍
1x00:思想
1x01:节点保存
1x02:核心操作 split
1x03:推平操作 assign
2x00:例题
2x01:CF896C
2x02:CF915E
3x00:总结

0x00 介绍

珂朵莉树(Chtholly Tree),又称 ODT(Old Driver Tree),一种数据结构,但似乎暴力到不能称之为数据结构。可以很好地骗分,在随机数据下十分有效,常用于将\([l, r]\) 赋值为 \(k\) 的时候,我们将这个操作称为推平操作

1x00 思想

前置芝士:set

主要的思想是将值相同的区间放在同一个节点里,保存在 set 中

时间复杂度为 \(O(n \log \log n)\)

1x01 节点保存

节点代码如下

struct Node{
	int l, r;
	mutable int val;
	Node(int l, int r, int val) : l(l), r(r), val(val){}
	bool operator < (const Node a) const{
		return l < a.l;
	}
};
set<Node> Chtholly;

这其中,mutable 十分成功地吸引了我们的注意力,mutable 意为「可变的」,因为在 set 中,所有的变量都是常量,若要修改某个值,需要取出再放回去,加上了 mutable,就可以突破这个限制,达到直接修改某个值的目的。

1x02 核心操作 split

这里先给出代码

auto split(int x)
{
	auto it = Chtholly.lower_bound(Node(x, 0, 0));
	if (it != Chtholly.end() && it -> l == x)return it;
	it--;
	if (it -> r < x)return Chtholly.end();
	int l = it -> l, r = it -> r, val = it -> val;
	Chtholly.erase(it);
	Chtholly.insert(Node(l, x - 1, val));
	return Chtholly.insert(Node(x, r, val)).first;
}

split 第一段代码是为了找出第一个 \(x \le l\) 的元素,如果这个元素的 \(l = x\) 时,直接返回找到的。

然后 it--, 若下一个元素的 \(r > x\),那么返回 set 的结尾。

接下来就是将他拆分开来,拆分成 \([l,x)\) 和 \([x,r]\),先删除原节点,再加入\([l,x)\) 和 \([x,r]\) 这两个新节点。

split 操作的意义在于它可以将这些序列 \([l,r]\) 的操作转换为 set 中 \([split(l),split(r+1))\),的操作。

1x03 推平操作 assign

理解了上面的代码,这里就应该很好理解了吧

void assign(int l, int r, int val)
{
	auto itl = split(l), itr = split(r + 1);
	for (auto it = itl; it != itr; it++)it -> val = val;
}

2x00 例题

2x01 例题一 CF896C

CF:CF896C
Luogu:CF896C

2x01x01 分析

万物之源。

操作 1 为区间加,像推平操作那样类似的方式即可

操作 2 为推平,直接用

操作 3 为区间第 \(k\) 小,用数组保存下这个区间的节点,然后询问

操作 4 为区间所有数的 \(x\) 次方之和 \(\bmod \ y\),用快速幂解决掉

2x01x02 代码

/*Code By Manipula*/
#include <bits/stdc++.h>
// #define Fileopen
// #pragma GCC optimize(2)
#define INF 0x3f3f3f3f
#define int long long
#define FOR(i, a, b) for (int i = a; i <= b; i++)
#define ROF(i, a, b) for (int i = a; i >= b; i--)
#define swap(x, y) x ^= y ^= x ^= y
#define sqrt(n) pow(n, 0.5)
#define sort stable_sort
#define mst(arr, num) memset(arr, num, sizeof(arr))
#define endl '\n'
using namespace std;
struct Node{
	int l, r;
	mutable int val;
	Node(int l, int r, int val) : l(l), r(r), val(val){}
	bool operator < (const Node a) const{
		return l < a.l;
	}
};
struct Rank{
	int val, num;
	Rank(int val, int num) : val(val), num(num){}
	bool operator < (const Rank a) const{
		return val < a.val;
	}
};
set<Node> Chtholly;
vector<Rank> RK;
auto split(int x)
{
	auto it = Chtholly.lower_bound(Node(x, 0, 0));
	if (it != Chtholly.end() && it -> l == x)return it;
	it--;
	if (it -> r < x)return Chtholly.end();
	int l = it -> l, r = it -> r, val = it -> val;
	Chtholly.erase(it);
	Chtholly.insert(Node(l, x - 1, val));
	return Chtholly.insert(Node(x, r, val)).first;
}
void assign(int l, int r, int val)
{
	auto itr = split(r + 1), itl = split(l);
	Chtholly.erase(itl, itr);
	Chtholly.insert(Node(l, r, val));
}
void add(int l, int r, int val)
{
	auto itr = split(r + 1), itl = split(l);
	for (auto it = itl; it != itr; it++)it -> val += val;
}
int rk(int l, int r, int x)
{
	RK.clear();
	auto itr = split(r + 1), itl = split(l);
	for (auto it = itl; it != itr; it++)
		RK.push_back(Rank(it -> val, it -> r - it -> l + 1));
	sort(RK.begin(), RK.end());
	for (auto it = RK.begin(); it != RK.end(); it++)
		if (x > it -> num)x -= it -> num;
		else return it -> val;
	return INF;
}
int qpow(int n, int k, int mod)
{
	int res = 1, rhs = n % mod;
	for (; k; k >>= 1, rhs = (rhs * rhs) % mod)
		if (k & 1)res = (res * rhs) % mod;
	return res;
}
int query(int l, int r, int x, int mod)
{
	auto itr = split(r + 1), itl = split(l);
	int res = 0;
	for (auto it = itl; it != itr; it++)
		res = (res + (it -> r - it -> l + 1) * qpow(it -> val, x, mod)) % mod;
	return res;
}
int n, T, seed, mx, qwq;
int rnd()
{
	int res = seed;
	seed = (seed * 7 + 13) % (int)(1e9 + 7);
	return res;
}
signed main()
{
	#ifdef Fileopen
		freopen(".in", r, stdin);
		freopen(".out", w, stdout);
	#endif
	cin >> n >> T >> seed >> mx;
	FOR(i, 1, n)Chtholly.insert(Node(i, i, (rnd() % mx) + 1));
	while (T--)
	{
		int opt = (rnd() % 4) + 1, l = (rnd() % n) + 1, r = (rnd() % n) + 1, x, mod;
		if (l > r)swap(l, r);
		if (opt == 3)x = (rnd() % (r - l + 1)) + 1;
		else x = (rnd() % mx) + 1;
		if (opt == 4)mod = (rnd() % mx) + 1;
		if (opt == 1)add(l, r, x);
		else if (opt == 2)assign(l, r, x);
		else if (opt == 3)cout << rk(l, r, x) << endl;
		else cout << query(l, r, x, mod) << endl;
	}
	return 0;
}

2x02 例题二 CF915E

CF:CF915E
Luogu:CF915E

2x02x01 分析

操作 1 和 2 都为推平操作,设非工作日为 0, 工作日为 1,那么就与上面的推平操作一样了,注意此题有一点卡常

2x02x02 代码

/*Code By Manipula*/
#include <bits/stdc++.h>
// #define Fileopen
// #pragma GCC optimize(2)
#define INF 0x3f3f3f3f
#define int long long
#define FOR(i, a, b) for (int i = a; i <= b; i++)
#define ROF(i, a, b) for (int i = a; i >= b; i--)
#define swap(x, y) x ^= y ^= x ^= y
#define sqrt(n) pow(n, 0.5)
#define sort stable_sort
#define mst(arr, num) memset(arr, num, sizeof(arr))
#define endl '\n'
using namespace std;
struct Node{
	int l, r, val;
	Node(int l, int r, int val) : l(l), r(r), val(val){}
	bool operator < (const Node a) const{
		return l < a.l;
	}
};
set<Node> Chtholly;
auto split(int x)
{
	auto it = Chtholly.lower_bound(Node{x, 0, 0});
	if (it != Chtholly.end() && it -> l == x)return it;
	it--;
	if (it -> r < x)return Chtholly.end();
	int l = it -> l, r = it -> r, val = it -> val;
	Chtholly.erase(it);
	Chtholly.insert(Node(l, x - 1, val));
	return Chtholly.insert(Node{x, r, val}).first;
}
int n, T, sum;
void assign(int l, int r, int val)
{
	auto itr = split(r + 1), itl = split(l);
	for (auto it = itl; it != itr; it++)sum -= (it -> r - it -> l + 1) * it -> val;
	Chtholly.erase(itl, itr);
	Chtholly.insert(Node(l, r, val));
	sum += val * (r - l + 1);
}
signed main()
{
	#ifdef Fileopen
		freopen(".in", r, stdin);
		freopen(".out", w, stdout);
	#endif
	cin >> n >> T; sum = n;
	Chtholly.insert(Node(1, n, 1));
	while (T--)
	{
		int opt, l, r;
		cin >> l >> r >> opt;
		assign(l, r, opt - 1);
		cout << sum << endl;
	}
	return 0;
}

3x00 总结

珂朵莉树是骗分好手,有推平操作都可以达到骗分的目的,若数据随机甚至会 AC

标签:Node,学习,return,val,Chtholly,int,笔记,朵莉树,split
From: https://www.cnblogs.com/Manipula/p/17909472.html

相关文章

  • 基于深度学习网络的疲劳驾驶检测算法matlab仿真
    1.算法运行效果图预览  2.算法运行软件版本matlab2022a 3.算法理论概述3.1疲劳检测理论概述      疲劳检测的原理是根据人体疲劳状态下的特征检测,和正常状态下的特征检测做对比。在做疲劳检测之前,首先需要分析人体在疲劳状态下与正常状态下的特征有哪些不......
  • LightGCL Simple Yet Effective Graph Contrastive Learning For Recommendation论文
    Abstract目前的图对比学习方法都存在一些问题,它们要么对用户-项目交互图执行随机增强,要么依赖于基于启发式的增强技术(例如用户聚类)来生成对比视图。这些方法都不能很好的保留内在的语义结构,而且很容易受到噪声扰动的影响。所以我们提出了一个图对比学习范式LightGCL来减轻基于CL......
  • 《架构师之路:软件架构之美》阅读笔记三
    《架构师之路:软件架构之美》是一本关于软件架构的入门书籍,作者李家智从自己的实践经验出发,结合了业内一些经典的案例和经验,系统地介绍了软件架构的基本概念、原则和方法。本书主要分为三个部分:第一部分介绍了软件架构的基本概念和原则;第二部分详细介绍了一些常用的软件架构模式,如......
  • 机器学习-线性分类-支持向量机SVM-软间隔-13
    目录1.总结SVM2.软间隔svm1.总结SVMSVM算法的基础是感知器模型,感知器模型与逻辑回归的不同之处?逻辑回归sigmoid(θx)映射到0-1之间给出预测概率感知器分类sign(θx)输出θx的符号,+1或者-1给出x是属于正样本还是负样本直接输出θx的值就是线性回归感知器......
  • 算法学习Day5 哈希的一天
    Day5哈希的一天ByHQWQF2023/12/13当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。笔记242.有效的字母异位词给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。示例 1:输入:s="anagram",t="nagaram......
  • 开源学习项目推荐
    @目录koodo-reader凤凰架构学习项目NPS内网穿透客户端koodo-reader项目地址:https://github.com/koodo-reader/koodo-reader介绍:一个开源的阅读器,阅读pdf也有目录,作为epub阅读器和pdf阅读器看资料挺好凤凰架构项目地址:https://github.com/fenixsoft/awesome-fenix这个项目......
  • 阅读笔记
    第四章是需求规格的说明,在这章中作者提出需要用图形和其他形式化模型来说明需求。需求规格说明用客户的叙述性需求作为输入,用构造规格说明模型作为输出,这些模型分为3组,即状态模型,行为模型和状态变化模型。对象的状态由它的属性和关联的取值来决定,状态规格说明提供系统的静态视图,通......
  • [Vue] vue学习笔记(11): 自定义事件 & 全局事件总线
    组件的自定义事件通过props可以将信息传递给子组件,那么当子组件需要向上传递信息的时候呢,除了使用props传递函数类的方法,我们还可以用自定义事件通过父组件给子组件绑定一个事件someEvent//App.vue<Student@someEvent='getStudentName'/>//methodsmethods:{ getStu......
  • CARAFE: Content-Aware ReAssembly of FEatures 可学习的上采样
    CARAFE:Content-AwareReAssemblyofFEatures*Authors:[[JiaqiWang]],[[KaiChen]],[[RuiXu]],[[ZiweiLiu]],[[ChenChangeLoy]],[[DahuaLin]]DOI:10.1109/ICCV.2019.00310Locallibrary初读印象comment::(CARAFE)提出了一种新的上采样方法。动机特......
  • 《程序员修炼之道:从小工到专家》阅读笔记(4)
    《程序员修炼之道:从小工到专家》阅读笔记(4)在阅读《程序员修炼之道:从小工到专家》第四章的过程中,我深受启发。这一章节的内容围绕代码的可维护性进行深入探讨,强调了代码不仅仅是实现功能的工具,更是程序员与同事、未来自己沟通的桥梁。首先,我深感使代码可维护的重要性。代码就像......