珂朵莉树

一种特殊的数据结构。

介绍

李欣隆发明。本质上并不是一种树形数据结构,思想是把一个区间按 \(value\) 划分成不少的小区间,然后暴力操作。

显然,这样做的复杂度完全依赖于小区间的多少,所以复杂度需要由区间推平操作保证。

在随机的数据下,可以证明每次的小区间期望有 \(\log_2n\) 个,并且常数极其小。所以常常可以通过 \(10^7\) 的数据。离散化?不存在的。

前置

你需要熟练的操作结构体。

比如你需要学习怎样重载运算符。

bool operator <(const& tt)const{ return ll<tt.ll; }

以及一些 \(set\) 的基本用法,还有迭代器的用法,当然,迭代器可以直接 \(auto.\)

erase(itl,itr);

这行可以直接清空两端点极其之间的所有元素。

\(\texttt{split}\)

设置一个结构体 \(node\),如下所示。

struct node{
	int ll,rr;	
	mutable int val;
	node(int L,int R=-1,int V=0): ll(L), rr(R), val(V) {}
	bool operator <(const node& tt)const { return ll< tt.ll;}
};
set<node> st;

之后还要考虑 \(split(pos).\)

用处如下:将树中含有下标 \(pos\) 的一段区间分成 \([l,pos-1], [pos,r]\) 两部分,返回一个左边区间的迭代器。

\(\texttt{assign}\)

区间推平操作。\(split\) 之后把中间的 \(erase\) 之后再 \(insert\) 一个较大的区间。

void assign(int ll,int rr,int val){
	auto itr=split(rr+1),itl=split(ll);
	st.erase(itl,itr);
	st.insert(node(ll,rr,val));
}
\(\texttt{Other function}\)

其他的函数大致如下形式:

void func(int ll,int rr){
	auto itr=split(rr+1),itl=split(ll);
	for(;itl!=itr;++itl) ...
}

比如说区间不同数计数:

int query(int ll,int rr){
	unordered_set<int> st2;
	auto itr=split(rr+1),itl=split(ll);
	for(;itl!=itr;++itl) if(itl->val) st2.insert(itl->val);
	return st2.size();
}

纯粹暴力。

posted @ 2024-04-05 13:22  ChihiroFujisaki  阅读(51)  评论(0)    收藏  举报