Willem, Chtholly and Seniorious(珂朵莉树)

小时候听说过珂朵莉树的大名,奈何当时没有专业知识看不懂。最近正好想起来了,来补上这个遗憾。

珂朵莉树(Chtholly Tree)又叫老司机树(ODT ,Old Driver Tree)。多年前,一位用户 Old Driver 在通过本题 Willem, Chtholly and Seniorious 时给出了不同于线段树的暴力解法,也就是今天的 ODT 。它以 s e t set set 为容器,使用 s p l i t split split 和 a s s ♂ i g n ass♂ign ass♂ign 两个核心函数,以及极其暴力的思想来实现。思路清晰简单,码量少(相对于线段树)。

不过珂朵莉树还是很容易卡掉的,在面对随机数据和优化一些东西的时候才比较不容易被卡。不过这个好写确实是好写,有时间可以看看 不会花太多时间的 。

珂朵莉树讲解


梦的开始 珂朵莉树板题

这个题由于是使用随机数据生成器来生成数据,所以数据和操作都是随机的,有 1 4 \frac14 41 的概率会将区间直接赋值为一个数,正好对应 a s s i g n assign assign 函数可以把区间合并成一个点的功能,大大降低时间复杂度。因此可以使用珂朵莉树。

code:

三个注意点:

一:

val 定义时需要使用 mutable 来修饰,表示是可变的数据,不然一些版本会报错:
[Error] assignment of member 'ODT::Node::val' in read-only object

(我估计应该是)一些版本不允许迭代器直接修改参数值,也就是迭代器有 const 属性

二:

讲解的博客中也提到了,SIT it2=split(r+1),it1=split(l);中顺序不应改变,先 split(r+1),再 split(l)。否则如果 l l l 和 r + 1 r+1 r+1 在同一个节点上,就会导致 split(l) 指向的节点被删掉,迭代器失效。

一般来说,如果删除的是set中迭代器指向的元素,那么这个迭代器将会失效。如果删除的是其他元素,通常来说,set中的其他迭代器应该保持有效。但是注意,进行容器修改操作后,所有迭代器都可能失效,迭代器失效通常与容器的结构变化有关。

三:

build() 函数中的 s.insert(Node(n+1,n+1,0)); 语句应当尽量写上。否则当 split(n+1) 的时候就会加入两个节点,范围分别是 l , n , n + 1 , n l,n,n+1,n l,n,n+1,n。

而且加入这个语句后,s.lower_bound() 一定不会访问到 s.end() 可以少写点判断代码。

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn=1e5+5;
typedef long long ll;

ll n,m,seed,vm;

ll rnd(){
	ll ret=seed;
	seed=(7ll*seed+13)%1000000007ll;
	return ret;
}

ll qpow(ll a,ll b,ll mod){
	ll ans=1,base=a;
	while(b){
		if(b&1){
			ans*=base;
			ans%=mod;
		}
		base*=base;
		base%=mod;
		b>>=1;
	}
	return ans;
}

struct ODT{
	#define SIT set<Node>::iterator
	struct Node{
		int l,r;
		mutable ll val;
		Node(int l,int r=-1,ll val=0):l(l),r(r),val(val){};
		bool operator<(const Node x)const{
			return l<x.l;
		}
	};
	set<Node> s;
	
	void build(int n){
		for(int i=1;i<=n;i++)
			s.insert(Node(i,i,rnd()%vm+1));
		s.insert(Node(n+1,n+1,0));
	}
	SIT split(int pos){
		SIT it=s.lower_bound(Node(pos));
		if(it!=s.end() && it->l==pos){
			return it;
		}
		it--;
		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;
	}
	void assign(int l,int r,ll x){
		SIT it2=split(r+1),it1=split(l);
		s.erase(it1,it2);
		s.insert(Node(l,r,x));
	}
	void add(int l,int r,ll x){
		SIT it2=split(r+1),it1=split(l);
		for(;it1!=it2;it1++)
			it1->val+=x;
	}
	ll rk(int l,int r,ll k){
		SIT it2=split(r+1),it1=split(l);
		vector<pair<ll,int> > t;
		t.clear();
		for(;it1!=it2;it1++)
			t.push_back(pair<ll,int>(it1->val,it1->r-it1->l+1));
		sort(t.begin(),t.end());
		for(auto x:t){
			if(x.second>=k)return x.first;
			else k-=x.second;
		}
	}
	ll pw(int l,int r,ll x,ll mod){
		SIT it2=split(r+1),it1=split(l);
		ll ans=0;
		for(;it1!=it2;it1++){
			ans=(ans+1ll*(it1->r-it1->l+1)*qpow(it1->val%mod,x,mod)%mod)%mod;
		}
		return ans;
	}
	
	void print(){
		for(auto x:s){
			printf("[%d,%d] val=%d\n",x.l,x.r,x.val);
		}
		puts("");
	}
	
	#undef SIT
}tr;

int main(){
	cin>>n>>m>>seed>>vm;
	tr.build(n);
//	tr.print();
	
	for(int i=1;i<=m;i++){
		ll 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()%vm+1;
		if(op==4)y=rnd()%vm+1;
		
		if(op==1){
			tr.add(l,r,x);
		}
		else if(op==2){
			tr.assign(l,r,x);
		}
		else if(op==3){
			cout<<tr.rk(l,r,x)<<endl;
		}
		else {
			cout<<tr.pw(l,r,x,y)<<endl;
		}
//		tr.print();
	}
	
	return 0;
}
相关推荐
乐迪信息1 小时前
港口船舶逆行怎么管?AI防爆摄像机搭载智能检测算法
大数据·人工智能·深度学习·算法·计算机视觉
Sirens.2 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
和裕2 小时前
全纸结构重型纸箱能否满足 1 吨以上设备出口熏蒸豁免要求?通关合规性全解析
大数据·运维·网络·人工智能·算法
tangguofeng3 小时前
不带头结点的链队操作集(不含InitFlag)(C语言版)
算法
苏打豆4 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的4 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙5 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11335 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY5 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录6 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt