珂朵莉樹(ODT)

tyccyt發表於2024-10-06

前言

主要是一種暴力思想。。。

本文來自 wiki 與洛谷題解的整合。

應用

主要是應付隨機資料(區間操作)

實現

有幾個核心操作。

set實現方法

定義

struct node
{
	intt l,r;//intt:long long
	mutable intt v;
	node(const intt &ll,const intt &rr,const intt &vv) : l(ll),r(rr),v(vv) {}
	bool operator <(const node &o)const 
	{
		return l<o.l;
	}
};
set<node>odt;

split 操作(分裂)

auto split(int x)
{
	auto it=odt.lower_bound(node(x,0,0));
	if(it!=odt.end()&&it->l==x)return it;
	it--;
	intt l=it->l,r=it->r,v=it->v;
	odt.insert(node(l,x-1,v));
	return odt.insert(node(x,r,v)).first;
}
  1. 如果分裂的點恰好是某個區間的左端點,就不用分裂,保留即可。
  2. 如果分裂的點在一個區間的中間節點,就將其分為 \([l,x-1]\)\([x,r]\) 這兩個區間
  3. 注意:odt.insert(node(x,r,v)).first這表示新加入的node的位置的迭代器(這是因為insert返回了一個pairfirst就只新加入的node的位置的迭代器了)

assign 操作(區間推平)

void assign(intt l,intt r,intt v)//intt:long long
{
	auto itr=split(r+1),itl=split(l);
	odt.erase(itl,itr);
	odt.insert(node(l,r,v));
}

將邊角餘料分裂出來,再將中間所有元素刪除,最後加入推平區間。

如下圖:

img

set的一個用法:erase(first,last)刪除迭代器在 \([first,last)\) 範圍內所有元素。

add 操作(區間加)

找到每一個段,暴力修改

void add(intt l,intt r,intt v)
{
	auto itr=split(r+1),itl=split(l);
	for(auto it=itl;it!=itr;it++)
	{
		it->v+=v;
	}
}

相關文章