珂朵莉樹 獻給世界上最幸福的女孩

2022-05-08 15:54:10 字數 4294 閱讀 9656

所以,我敢肯定,現在的我.不管別人怎麼說,都一定是世界上最幸福的女孩。

——chtholly·nota·seniorious

珂朵莉樹(chtholly_tree),原名老司機樹(old diver tree,odt),但是叫做珂朵莉樹是廣大 珂學家們 oiers所喜聞樂見的,所以我們一般叫她珂朵莉樹。發明者是著名的 毒瘤lxl同志。

珂朵莉很強,珂朵莉樹更強,簡直是區間維護的一姐(個人觀點勿噴awa)

1. 有推平操作(區間賦值),且資料隨機(不過出題人一般不會惡意卡她)

2. 尤其是有許多奇怪操作難以維護的題目(當然也不一定要有...)

(開了o2就放心用吧)

舉個栗子:

下面是在luogu上的一些可以用珂朵莉樹ac的題目

黑 (noi/noi+/ctsc)

cf896c willem, chtholly and seniorious

p3215 [hnoi2011]括號修復 & [jsoi2011]括號序列

紫 (省選/noi-)

p2787 語文1(chin1)- 理理思維

cf915e physical education lessons

p2572 [scoi2010]序列操作

p4979 礦洞:坍塌

p4344 [shoi2015]腦洞**儀

藍 (提高+/省選-)

p2894 [usaco08feb]酒店hotel

綠 (普及+/提高)

p3740 [haoi2014]貼海報

黃 (普及/提高-)

p2082 區間覆蓋(加強版)

u59472 校門外的樹plus

橙 (普及-)

p1496 火燒赤壁

p1204 [usaco1.2]擠牛奶milking cows

紅 (入門)

p1047校門外的樹

可見其適用性之廣。可以說,只要是有區間賦值操作的區間維護問題,幾乎都可以用珂朵莉樹完成。

首先她是建立在stl::set的基礎上的一種暴力資料結構,基本思路是把元素值同為v的區間 [l,r] 表示成三元組(l,r,v)

並用set維護它們。

珂朵莉樹的各個區間一定不重不漏的覆蓋全集

基♂操定義set

按照我的習慣,自然是要先上**的

struct

node

bool

operator

<(const node& o)const

};set

s;#define it set::iterator //方便

當然,也可以這麼寫

friend bool

operator

<(node a,node b)

typedef

set::iterator it;

至於建構函式,隨你怎麼寫。

split 分割區間

聯絡分塊,操作時把乙個區間破成幾份是常有的事兒。

it split(int

pos)

分割區間使得pos在乙個區間的左端點並返回該區間的指標。

lower_bound找後繼,pos會被轉換為node(pos),找不到返回s.end()

用upper_bound也行,但是要跟著修改 ++it 和 其他操作都要先 split(l)後split(r+1),這個看後面。

如果已經滿足,返回;

否則一定在上乙個區間。 (看看上面的紅字)

刪除,增加就行了。

s.insert()的返回值是pair型別,其first為指向新結點的指標

assign推平操作

void assign(int l,int r,int

k)

十分簡單。不過注意如果先l再r可能會使l所在的塊被分割,使得

有點像splay

的刪除,兩頭一夾,中間刪除。

最後再補上一塊兒。

s.erase(itl,itr)  刪除[itl,itr)的元素

sum區間求和

int sum(int l,int

r)

.for(it it=itl;..;..)可以寫成for(;itl!=itr;++itl)

..好簡單 = = (可真暴力)

不說了,不過注意在迴圈時使用 != 所以itr訪問不到。

add區間加

void add(int l,int r,int

v)

區間乘等以此類推。這裡用了itl的迴圈寫法。

玄學操作

乙個比乙個暴力,但是就是跑的飛快 = =

reverse 區間取反(維護01序列)

void reverse(int l,int

r)

顯然。證畢。 = =

invent區間取負

void invert(int l,int

r)

同上。得證。= =

swap區間翻轉(你沒看錯,這不是splay的函式)

void swap(int l,int

r)

這裡用乙個vector來裝pair型別,分別是值和區間長度。

最後反過來按照區間長度和當前的 l或r 計算區間位置即可。用l和r都行。

cont查詢最長連續區間

int cont(int l,int r)

return

max(maxn,res);

}

當然你可以進行魔改(反正本來這些函式都是魔改的產物)搞成查詢指定v的連續區間、不同v的區間的個數、返回該區間的v等等...= =

kth區間第k小(這裡真不是splay... = =)

ll kth(int l,int r,int x)

直接sort,怕什麼qwq

懶得改ll和x小什麼的了,求k大,求某數排名都差不多的.....

sum區間冪次和(沒有函式名可以用了,將就一下吧qwq)

ll sum(int l,int r,int x,int

y)

這裡是區間x次冪在mod y。

快速冪自己寫= =

常見的就這些(霧)但是還可以寫很多奇怪的函式,比如 p4344 [shoi2015]腦洞**儀裡面的求前若干個零 ... etc

作為暴力結構我們要有暴力的信心,題目什麼要求都能魔改出來,時刻記住,你是暴力,你比別人好除錯  = = 還比別人短

就算你不相信自己,也要相信珂朵莉。

雖然說是這麼說,但是基礎的優化還是要有的。

玄學優化:merge區間(隨機)合併

先別急抄這個**,下面還有。

void

merge(it it)

每個函式結束,只要不影響,都呼叫一下。

只要能多合併幾次你就賺了。

有時有奇效。

這裡也可以判斷 it != s.end()/s.begin()

不過用assign會慢(而且就不能在assign裡面呼叫了qwq)

於是有(更優秀qwq)

void

merge(it it)

else

if(itl->v==it->v)

else

if(itr->v==it->v)

}

通常的 建樹方式

s.insert(i,i,a[i]);
顯然這很慢 ...qwq

一般這樣做:

for(int i=2,l=1;i<=n+1;++i)

if(i==n+1||a[i]!=a[i-1

]) s.insert(node(l,i-1,a[i-1])),l=i;

當然有些題目可以全部賦初值....= = 就是 s.insert(node(1,n,0))

某些題目區間長度會比較奇怪(如p1496 火燒赤壁),當 l=r 時題目視作不存在

這時如果考慮修改各個函式則會非常麻煩,甚至導致奇怪的錯誤,於是,使用 s.insert(node(l,r-1))即可...

相當於把 [l,r) 作為 [l,r-1] 儲存,沒有問題。

希望大家都能學會這個好聽,好寫,好用的資料結構!

珂朵莉樹學習筆記

珂朵莉樹是一種基於 set 的暴力資料結構,真的很好懂 因為暴力鴨 又叫 old driver tree 老司機樹 適用於區間賦值,資料隨機.首先來講講它的思想,它把區間 1,n 分成若干個 l i,r i l i,r i 內的數都一樣,為 w i 舉栗子 區間 1,5 的初值為 1 現在只有乙個區...

校門外的樹 珂朵莉樹

題目描述 某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是11公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸00的位置,另一端在ll的位置 數軸上的每個整數點,即0,1,2,l0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表...

CodeForces 896C 珂朵莉樹

傳送門 用set搞的比較神奇的樹吧,玄學時間複雜度,簡潔好寫,無聊學了用來水題再好不過了 include include include include include include include include include include include include define x ...