神奇的暴力數據結構——ODT(珂朵莉樹)


前言

\(ODT\),即珂朵莉樹,又稱老司機樹\(Old\ Driver\ Tree\))。

它是一個十分暴力的數據結構,可以用於各種亂搞,也非常的實用。

當然,這全要基於一個基本條件:數據隨機

主要思想

\(ODT\)的主要思想就是把一個元素完全相同的區間合並成一個節點,然后用\(set\)維護(我也不知道為什么稱其為“樹”)。

而在數據隨機的情況下,節點的期望個數是很少的,因此復雜度也就比較低。

核心操作: \(Split\)操作

\(ODT\)的核心操作就是\(Split\)操作。

\(Split(x)\)的作用是分裂出一個以\(x\)為左端點的區間

對於這個操作,我們先用\(set\)\(lower\_bound\)函數,找到左端點不小於\(x\)的第一個區間。

如果此時找到的區間左端點已經為\(x\)了,則直接返回這個區間。

否則,我們就將迭代器移動到上一個位置,而這個區間才是我們要分裂的。

設這個區間為\([l,r]\)

則我們應將它分裂成\([l,x-1]\)\([x,r]\)兩部分。

所以我們先將\(l,r\)用變量存儲下來,然后在\(set\)中清除原來的區間,並將新的區間插入\(set\)

然后\([x,r]\)這個區間就是我們所要找的,將其返回即可。

這個操作代碼如下:

I IT Sp(CI x)//分裂出一個以x為左端點的區間
{
	IT t;if((t=S.lower_bound(Il(x)))!=S.end()&&t->l==x) return t;//如果此時找到的區間左端點已經為x了,則直接返回這個區間
	RI l=(--t)->l,r=t->r,v=t->v;S.erase(t),S.insert(Il(l,x-1,v));//將迭代器移動到上一個位置,先將l,r用變量存儲下來,然后在set中清除原來的區間,並將新的區間插入set
	return S.insert(Il(x,r,v)).first;//區間[x,r]就是我們所要找的,將其返回即可
}

推平操作:\(Assign\)操作

顯然,光有\(Split\)操作顯然會\(T\)飛。

所以我們就需要一個推平操作,把某段區間合並成一個節點。

則我們把這個區間的左端點,以及右端點的下一個位置提出,然后刪除它們之間的所有節點(包括左端點但不包括右端點的下一個位置),再把新的節點加入即可。

這個操作代碼如下:

I void Assign(CI x,CI y,CI v)//推平操作
{
	IT tr=Sp(y+1),tl=Sp(x);S.erase(tl,tr),S.insert(Il(x,y,v));//把這個區間左端點及其之后、右端點下個位置之前的所有節點刪除,然后插入新的節點
}

其余操作

其余操作就沒什么好說的了,直接暴力掃一遍即可,真是不能再暴力了。

例題

下面給出一道例題:【BZOJ1858】[SCOI2010] 序列操作(ODT裸題)(正解是線段樹)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM