珂朵莉树

前言

因为隔壁大佬自学了珂朵莉树,所以我心血来潮,也学了一下

定义

用自己的话谈一谈珂朵莉树:

珂朵莉树,简称\(ODT(Old\space Driver\space Tree)\),即老司机树

\(set\)维护,每个区间为一个元素,存放在\(set\)(那它怎么叫树呢)

每个区间的元素数值相同

struct node
{
	int l,r;
	mutable LL val;	
	node(int l1,int r1 = -1,LL val1 = 0){
		l = l1;
		r = r1;
		val = val1;
	}
	bool operator < (const node &px)const {
		return l < px.l;
	}
};

小笔记:\(mutable\) 的中文意思是可变的,在迭代器中,结构体中的值会被当成常量,即有\(const\)的前缀,本来是不能被改变的,但是加了\(mutable\) 就可以被改变了

适用于区间赋值和其它操作且题目数据随机的情况

其实就是大暴力

正题

一、split函数

这个函数是珂朵莉树的核心

通过百度翻译可知,这个函数的意思是分裂

你想一想,如果现在有一个区间是\(l\)$r$,假设我们要查找的是$l$\(x(l\le x< r)\),没有现成的区间,我们就可以把这个区间删除,分成\(l\)$x$和$(x+1)$\(r\)

于是就有了现成的区间

或者说我们负责保证一定有一个端点\(x\)存在

那么我们就可以这么实现:

#define IT set<node>::iterator
IT split(int pos)//分裂 
{
	IT it = s.lower_bound(node(pos));
	if(it != s.end() && it->l == pos)
		return it;
	--it;
	int l = it->l,r = it->r;
	LL dz = it->val;
	s.erase(it);
	s.insert(node(l,pos-1,dz));
	return s.insert(node(pos,r,dz)).first;
	//JZMの小科普:set::insert返回pair<iterator,bool> ,分别为新加入元素迭代器、是否加入成功。
}

至于为什么要返回迭代器

那是因为为了方便我们之后的操作

二、merge函数

这个函数是珂朵莉树的灵魂

可以快速减少区间的个数,降低运行时间

我们只需要删除原来的\(l\)~\(r\),再重新加入就行了

删除的时候可以用内置函数\(erase\)实现

void merg(int l,int r,LL val)//合并l~r 
{
	IT R = split(r+1),L = split(l);
	s.erase(L,R);
	//JZMの小科普:set::erase(iterator,iterator)可以左闭右开地删除元素。
	s.insert(node(l,r,val));
} 

这里要注意的是\(merge\)是关键字,所以我用了\(merg\)代替

三、其它操作

暴力才是本质

这里只列举一个操作:区间加

void Add(int l,int r,LL val)//暴力加就完事了 
{
	IT R = split(r+1),L = split(l);
	for(;L != R;++ L)
		L->val += val;
}

真的是暴力啊!!!

反正其它的都是暴力,听了这么多,你自己一定能根据题目随机应变码出来的

练习

板题(洛谷)

板题(CodeForces)

Physical Education Lessons(洛谷)

Physical Education Lessons(CodeForces)

代码

板题代码

//12252024832524
#include <set>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#define IT set<node>::iterator
using namespace std; 

typedef long long LL;
const int MAXN = 10005;
int n,m,vmax;
LL seed;
struct node
{
	int l,r;
	mutable LL val;	
	node(int l1,int r1 = -1,LL val1 = 0){
		l = l1;
		r = r1;
		val = val1;
	}
	bool operator < (const node &px)const {
		return l < px.l;
	}
};
set<node> s;

int Read()
{
	int x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
void Put(LL x)
{
	if(x > 9) Put(x/10);
	putchar(x%10^48);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}
LL rnd()
{
	LL ret = seed;
	seed = (seed * 7 + 13) % 1000000007;
	return ret;
}
LL qpow(LL x,int y,int MOD)
{
	x %= MOD;
	LL ret = 1;
	while(y)
	{
		if(y & 1)
			ret = ret * x % MOD;
		x = x * x % MOD;
		y >>= 1; 
	}
	return ret;
}
IT split(int pos)//分裂 
{
	IT it = s.lower_bound(node(pos));
	if(it != s.end() && it->l == pos)
		return it;
	--it;
	int l = it->l,r = it->r;
	LL dz = it->val;
	s.erase(it);
	s.insert(node(l,pos-1,dz));
	return s.insert(node(pos,r,dz)).first;
	//JZMの小科普:set::insert返回pair<iterator,bool> ,分别为新加入元素迭代器、是否加入成功。
}
void merge(int l,int r,LL val)//合并l~r 
{
	IT R = split(r+1),L = split(l);
	s.erase(L,R);
	//JZMの小科普:set::erase(iterator,iterator)可以左闭右开地删除元素。
	s.insert(node(l,r,val));
} 
void Add(int l,int r,LL val)//暴力加就完事了 
{
	IT R = split(r+1),L = split(l);
	for(;L != R;++ L)
		L->val += val;
}
LL rankk(int l,int r,int k)//暴力跑就完事了 
{
	vector<pair<LL,int> > v;
	IT R = split(r+1),L = split(l);
	for(;L != R;++ L)
		v.push_back(make_pair(L->val,L->r - L->l + 1));
	sort(v.begin(),v.end());
	vector<pair<LL,int> >::iterator it;
	for(it = v.begin();it != v.end();++ it)
	{
		k -= it->second;
		if(k <= 0)
			return it->first;
	}
}
LL mi(int l,int r,int x,int MOD)
{
	IT R = split(r+1),L = split(l);
	LL ret = 0;
	for(;L != R;++ L)
		ret = (ret + qpow(L->val,x,MOD) * (L->r - L->l + 1) % MOD) % MOD;
	return ret;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read();
	m = Read();
	seed = Read();
	vmax = Read();
	for(int i = 1;i <= n;++ i)
		s.insert(node(i,i,(rnd() % vmax) + 1));
	for(int i = 1;i <= m;++ i)
	{
		int op = (rnd() % 4) + 1;
	    int l = (rnd() % n) + 1;
	    int r = (rnd() % n) + 1;
		int x,y;
	    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)
			merg(l,r,x);
		else if(op == 3)
			Put(rankk(l,r,x));
		else if(op == 4)
			Put(mi(l,r,x,y));
		if(op >= 3)
			putchar('\n');
	}
	return 0;
}

Physical Education Lessons代码

//12252024832524
#include <set>
#include <cstdio>
#include <algorithm>
#define IT set<node>::iterator
using namespace std; 

typedef long long LL;
const int MAXN = 10005;
int n,tot;

int Read()
{
	int x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
void Put1(int x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
void Put(int x)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}

struct node
{
	int l,r;
	mutable bool val;
	node(){}
	node(int l1,int r1 = -1,bool val1 = 0){
		l = l1;
		r = r1;
		val = val1;
	}
	bool operator < (const node &px)const {
		return l < px.l;
	}
};
set<node> s;

IT split(int x)
{
	IT it = s.lower_bound(node(x));
	if(it != s.end() && it->l == x)
		return it;
	it--;
	int l = it->l,r = it->r;
	bool dz = it->val;
	s.erase(it);
	s.insert(node(l,x-1,dz));
	return s.insert(node(x,r,dz)).first;
}
void merg(int l,int r,bool val)
{
	IT R = split(r+1),L = split(l);
	for(IT it = L;it != R;++ it)
	{
		if(val == 1 && it->val == 0) tot += (it->r - it-> l + 1);
		if(val == 0 && it->val == 1) tot -= (it->r - it-> l + 1);
	}
	s.erase(L,R);
	s.insert(node(l,r,val));
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	tot = n = Read();
	s.insert(node(1,n,1));
	for(int Q = Read(); Q ;-- Q)
	{
		int l = Read(),r = Read(),opt = Read();
		merg(l,r,opt-1);
		Put(tot);
		putchar('\n');
	}
	return 0;
}

By The Way

本博客借鉴了两位大佬的博客,分别是:

一号大佬JZM JZM orz or2 orz

二号不知名大佬 orz or2 orz

posted @ 2020-07-28 16:32  皮皮刘  阅读(95)  评论(0编辑  收藏  举报