首页 > 其他分享 >[数据结构] 珂朵莉树

[数据结构] 珂朵莉树

时间:2024-07-29 20:51:19浏览次数:7  
标签:set iterator pos long 朵莉树 区间 数据结构 spilt

介绍

珂朵莉树,学名珂朵莉树,又学名老司机树( $ ODT $ ),常用来解决“区间推平”(把区间改为某一个数)等的操作,只适用于随机数据,可以定向卡掉;

其实这玩意就是暴力,没啥可说的,分块都比不上她暴力;

但人家毕竟是,所以对于一些题还是有用的;

实现

只要你会 $ C++ \ STL $ 里的 $ set $,搞定她完全不是问题;

当然,你还需要一些基本的指针操作;

主要思想:维护一段序列的所有连续的子区间(这里的“连续”指的是值连续);

对于 $ set $ 里的每一个元素,其为三元组,记录 $ l, r, v $,分别代表本段连续区间的左端点,右端点,值;

当然,$ set $ 中的元素是按 $ l $ 升序排列的;

声明:

struct sss{
	long long l, r;
	mutable long long v;
	bool operator <(const sss &A) const {
		return l < A.l;
	}
};

操作一 spilt

分裂操作,即指定一个 $ pos $,将整个序列分成两部分;

显然,最多只会对一个子区间进行操作;

借助 $ set $ 中的 $ lower \ bound $ 函数,我们可以快速查找出 $ pos $ 在哪个子区间里,此时会有这么几种情况:

  1. 此区间的 $ l = pos $;

直接返回此区间即可;

  1. 此区间的上一个区间的 $ r < pos $;

我们可以发现,此时 $ pos $ 太大了,已经超出了区间长度,所以直接返回迭代器即可;

  1. $ pos $ 在此区间的上一个区间中;

把此区间的上一个区间拆分成 $ l, pos - 1, v $ 和 $ pos, r, v $ 两个区间即可;

一个技巧:$ set $ 的 $ insert $ 函数有一个返回值,是 $ pair $ 类型的,$ first $ 返回插入元素的迭代器,$ second $ 返回这个元素是否被插入(因为 $ set $ 不可重);

set<sss>::iterator spilt(long long pos) {
	set<sss>::iterator it = s.lower_bound(sss{pos, 0, 0});
	if (it != s.end() && it -> l == pos) return it;
	it--;
	if (it -> r < pos) return s.end();
	long long l = it -> l;
	long long r = it -> r;
	long long v = it -> v;
	s.erase(it);
	s.insert(sss{l, pos - 1, v});
	return s.insert(sss{pos, r, v}).first;
}

注:$ it -> l $ 等价于 $ *it.l $;

操作二 assign

区间推平操作,设要修改的区间为 $ [l, r] $,我们可以先 $ spilt(r - 1) $,再 $ spilt(l) $,(顺序不能颠倒,不然会 $ RE $),最后删除这两步操作所对应的迭代器之间的所有元素(子区间),并插入要修改的元素(区间)即可;

void assign(long long l, long long r, long long x) {
	set<sss>::iterator rit = spilt(r + 1), lit = spilt(l);
	s.erase(lit, rit);
	s.insert(sss{l, r, x});
}

注:$ s.erase(a, b) $ 指的是删除 $ [a, b) $ 之间的元素;

操作三 其它暴力操作

几乎所有区间上的操作,只要你会暴力,就能用她做;

对于一段要操作的区间 $ [l, r] $,直接暴力遍历其中所有的元素,在进行操作即可;

例题:CodeForces 896C

对于第三个操作,发现用线段树不太好做,又发现数据随机,所以直接珂朵莉树搞它就行;

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
long long n, m, seed, vmax;
long long a[1000005];
struct sss{
	long long l, r;
	mutable long long v;
	bool operator <(const sss &A) const {
		return l < A.l;
	}
};
set<sss> s;
set<sss>::iterator spilt(long long pos) {
	set<sss>::iterator it = s.lower_bound(sss{pos, 0, 0});
	if (it != s.end() && it -> l == pos) return it;
	it--;
	if (it -> r < pos) return s.end();
	long long l = it -> l;
	long long r = it -> r;
	long long v = it -> v;
	s.erase(it);
	s.insert(sss{l, pos - 1, v});
	return s.insert(sss{pos, r, v}).first;
}
void assign(long long l, long long r, long long x) {
	set<sss>::iterator rit = spilt(r + 1), lit = spilt(l);
	s.erase(lit, rit);
	s.insert(sss{l, r, x});
}
long long rnd() {
	long long ret = seed;
	seed = (seed * 7 + 13) % 1000000007;
	return ret;
}
void add(long long l, long long r, long long d) {
	set<sss>::iterator rit = spilt(r + 1), lit = spilt(l);
	for (set<sss>::iterator it = lit; it != rit; it++) {
		it -> v += d;
	}
}
vector<pair<long long, long long> > v;
long long ask_kth(long long l, long long r, long long k) {
	set<sss>::iterator rit = spilt(r + 1), lit = spilt(l);
	v.clear();
	for (set<sss>::iterator it = lit; it != rit; it++) {
		v.push_back({it -> v, it -> r - it -> l + 1});
	}
	sort(v.begin(), v.end());
	long long o = 0;
	while(1) {
		k -= v[o].second;
		if (k <= 0) return v[o].first;
		o++;
	}
}
long long ksm(long long a, long long b, long long c) {
	long long ans = 1;
	while(b) {
		if (b & 1) ans = ans * a % c;
		a = a * a % c;
		b >>= 1;
	}
	return ans;
}
long long mo(long long l, long long r, long long x, long long y) {
	set<sss>::iterator rit = spilt(r + 1), lit = spilt(l);
	long long ans = 0;
	for (set<sss>::iterator it = lit; it != rit; it++) {
		ans = (ans + ksm(it -> v % y, x, y) * (it -> r - it -> l + 1) % y) % y;
	}
	return ans;
}
int main() {
	cin >> n >> m >> seed >> vmax;
	for (long long i = 1; i <= n; i++) {
		a[i] = (rnd() % vmax) + 1;
		s.insert(sss{i, i, a[i]});
	}
    for (long long i = 1; i <= m; ++i) {
        long long op, l, r, x, y;
        op = (rnd() % 4) + 1;
        l = (rnd() % n) + 1;
        r = (rnd() % n) + 1;
        if (l > r) swap(l, r);
        if (op == 3) {
            x = (rnd() % (r - l + 1)) + 1;
        } else {
            x = (rnd() % vmax) + 1;
        }
        if (op == 4) {
            y = (rnd() % vmax) + 1;
        }
        if (op == 1) {
        	add(l, r, x);
        } else if (op == 2) {
			assign(l, r, x);
        } else if (op == 3) {
        	cout << ask_kth(l, r, x) << endl;
        } else if (op == 4) {
        	cout << mo(l, r, x, y) << endl;
        }
    }
	return 0;
}

标签:set,iterator,pos,long,朵莉树,区间,数据结构,spilt
From: https://www.cnblogs.com/PeppaEvenPig/p/18331045

相关文章

  • 【数据结构】排序
    1.排序的概念及其运用1.1排序的概念排序:指的是将一组数据(通常是一个列表、数组或任何有限集合)按照某种特定的顺序重新排列的过程。这个特定的顺序可以是升序(从小到大)、降序(从大到小)或者根据自定义的规则进行排序。稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的......
  • 数据结构优化DP
    51nod-基因匹配+luogu-【模板】最长公共子序列本题重在转化。由于最长公共子序列的下标是一个最长上升子序列,所以我们可以考虑把数字映射成下标,有多个就要倒序把每个值映射成多个不同的值,因为一个数有多种下标都是可取的。51nod-3976-最长序列与基本问题相同,但是需要根据长度插......
  • 好玩的数据结构qwq
    从2024.7.29开始记录。代码不放可能是因为我没写。1.P7470[NOIOnline2021提高组]岛屿探险先考虑\(b_i>d_j\)的情况。那么答案就是\(\sum[a_i\oplusc_j\led_j]\)。我们把\(a_i\)插入\(01\text{trie}\)中。然后我们从上往下走,走到深度为\(h\)的节点,那么代......
  • 【数据结构】排序算法
    目录排序冒泡排序选择排序直接插入排序希尔排序堆排序归并排序快速排序排序排序的概念:假设含有n个记录的序列为{R1,R2,R3,···,Rn},其相应的关键字分别为{K1,K2,K3,···Kn},需确定1,2,3,···,n的一种排列P1,P2,···,Pn,使其相应的关键字满足Kp1<=Kp2<=K......
  • 山东大学数据结构与算法实验13最小生成树(Prim算法/Kruskal算法)
    A : Prim算法题目描述使用prim算法实现最小生成树输入输出格式输入第一行两个整数n,e。n(1≤n≤200000)代表图中点的个数,e(0≤m≤500000)代表边的个数。接下来e行,每行代表一条边:ijw 表示顶点i和顶点j之间有一条权重为w的边输出最小生成树所有边的......
  • 最细哈希表相关的力扣题和讲解和Java、C++常用的数据结构(哈希法)来源于代码随想录,十分
    20240725一、什么时候适用什么样的结构。1.java中1.1HashSet:1.2TreeSet:1.3LinkedHashSet:1.4HashMap:1.5TreeMap:1.6LinkedHashMap:1.7总结2.c++中2.1std::unordered_set:2.2std::set:2.3std::multiset:2.4std::unordered_map:2.5std::map:2.6std::multimap:3代码......
  • 浅谈简单的数据结构1(树状数组 、线段树)(c++)
    *_*课间休息后的知识点轰炸树状数组引入给定长为n的序列a,q次操作,每次查询一段区间的和,或修改一个数的权值。1≤n,q≤5×10^5,0≤a_i≤10^9。分析如果没有修改操作,这是一道非常简单的前缀和题。假如我们修改前缀和数组,查询就还是O(1)的,是否可行呢?当然不行。考虑......
  • 408 数据结构线性表算法
    第一章线性表定义:线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列。线性表的表示:若用L命名,表示:L=(a1,a2,a3,a4,a5,……,an)线性表的逻辑特性:a1:唯一的表头元素an:唯一的表尾元素除去a1:每个元素有且仅有一个直接前驱除去an:每个元素有且仅有一个直接后继......
  • 408数据结构树算法
    第四章树4.1二叉树的顺序存储#defineMAXSIZE16typedefintElemType;typedefstruct{ ElemTypedata[MAXSIZE]; intsize;}Tree;//初始化二叉树voidinitTree(Tree&T){ for(inti=0;i<MAXSIZE;i++){ T.data[i]=0; //假设0表示空节点 } T.size=0......
  • 408 数据结构图算法
    第五章图5.1图的邻接矩阵存储//无向图的邻接矩阵存储#defineMAXSIZE16 //图的最大顶点个数typedefintVertexType; //顶点类型typedefintEdgeType; //边类型typedefstruct{ VertexTypeVex[MAXSIZE]; //图的顶点集 EdgeTypeEdge[MAXSIZE][MAXSIZE]; //图的边......