模板 線段樹合併

2021-10-12 02:51:51 字數 1949 閱讀 5648

這是線段樹的最後乙個知識點啦,終於不用繼續練碼量超大的線段樹了,因為筆者已經掌握了~

例題:n只奶牛構成了乙個樹形的公司,每個奶牛有乙個能力值pi,1號奶牛為樹根。

問對於每個奶牛來說,它的子樹中有幾個能力值比它大的。

solution:

做法是每個點開一棵線段樹,插入這個結點上的數,根節點就為這個點的序號。如果能把乙個結點的線段樹的資訊在合理的時間內全部插入(或者說「合併」)到它父親的線段樹中,就可以由下往上做一遍樹上遞推,這樣每個結點的線段樹都儲存的是整棵子樹的資訊了。

先放**吧:

int

merge

(int p,

int q,

int l,

int r)

int mid=

(l+r)

>>1;

t[p]

.lson=

merge

(t[p]

.lson,t[q]

.lson,l,mid)

; t[p]

.rson=

merge

(t[p]

.rson,t[q]

.rson,mid+

1,r)

;// t[p].sum=t[t[p].lson].sum+t[t[p].rson].sum;

t[p]

.sum+

=t[q]

.sum;

//they are the same

return p;

}

這個**還是相當好理解的,無需贅述。下面來證明一下複雜度。(我想了一中午終於想出乙個超簡潔的證明 —— 本來以為會很複雜的)

從**中可以看出合併兩棵樹的複雜度約等於這兩棵樹 重合 的結點數。假如初始所有的線段樹點數總和為 n

nn 。因為只要合併兩個節點,節點總個數就會少掉乙個,所以複雜度應該是 o(n

)o ( n )

o(n)

的。所以不是所有情況下的線段樹合併都是 o(n

log⁡

n)

o ( n log ⁡ n )

o(nlog

⁡n) 的。

一般情況下我們只會對每個節點開動態開一條鏈,所以 n=n

log⁡

nn = n log ⁡ n

n=nlog

⁡n,複雜度才會是 o(n

log⁡

n)

o ( n log ⁡ n )

o(nlog

⁡n) 。

哇怎麼這麼短就寫完了 ……

update:「abc183f」confluence

題意:n個人,每個人屬於乙個班級ci,這些人會有些小團體(並查集)

兩種操作:

1 a b,將a所在的集體和b所在的集體合併

2 x y,問在x的集體中有多少人在y班

第一種做法啟發式合併,每次將點數較少的接到點數較多的上面。具體可以用map

mapma

p之類的stl

stlst

l來存集合。

第二種方法是線段樹合併。我們把乙個點所含的種類 [1,

2e5]

[1,2e5]

[1,2e5

] 看成乙個樹的結構,時間複雜度是嚴格 o(n

logn

)o(nlogn)

o(nlog

n)的。這個想法很妙。我們把乙個線性的單點合併放到動態開點線段樹上,這樣每次合併乙個點都刪除了乙個點,保證了演算法的高效。

第二種演算法的時間複雜度顯然是優於第一種的,第一種做法只能「單個搬運」,導致合併代價是不穩定的。而第二種則把若干子樹進行「整體搬運」,我們也通過理論證明了它時間上界和優秀的搬運性質(我們發現它在整個合併過程中沒有新建點)。

Hotel 線段樹區間合併模板題

有n個車位,一開始全是空的。m個要求,1 k,表示有k輛車要停,且位置要連續,找到編號最小的位置輸出,如果停不下,就輸出0 2 x k,表示從x位置開始,有連續k輛車開走。1代表有空位,0代表沒有空位。tr m left代表從左端點向右,連續1的區間長度,tr m right代表從右端點向左連續1的...

線段樹合併

做永無鄉的時候,以為是主席樹合併,後來感覺不對勁,唔。x和y是兩顆樹的根。這個演算法是從歸併演算法那引申的。實際運作的時候,考慮到了線段樹的本質 線段樹有效節點就是葉子節點。好像是句廢話。其實不是,這句話啟發我們並不需要合併一整棵樹,我們只需要處理好葉子節點,考慮把y樹合併到x上,那麼把y樹的葉子節...

線段樹合併

今天寫dsu on tree 的時候發現不會寫線段樹合併,於是滾來寫線段樹合併部落格 對於值域相同的兩個權值線段樹x xx和y yy 假設把y yy合併到x xx上 每個節點有兩種情況 其中至少有乙個節點沒有權值 x y x y x y 直接x x y x x y x x y x 0?y x x 0...