話說自己搞的樹鏈剖分疑似O m logn loglogn 的複雜度,不知哪個神犇能證明或舉反例嗎?

時間 2021-06-05 05:43:25

1樓:

對於樹鏈剖分,常見的做法是按照輕重鏈進行剖分

然後用一棵全域性線段樹維護整棵樹按dfs序構成的序列

這種寫法的優勢有:實現方便、支援可持久化、支援子樹操作

對於這種做法,複雜度確實是 的,考慮一棵滿二叉樹即可

但是,如果只需要支援鏈上操作,那麼可以對每條實鏈都用一棵線段樹進行維護

在這種情況下,是否存在著比輕重鏈剖分更優的剖分方法呢?

在這種情況下,是否存在著比 更優的複雜度呢?

樹上一點到根的路徑會經過若干條實鏈,我們分別計算每條實鏈的貢獻

如果一條實鏈從頭到尾都被走過了,那麼它的貢獻是 1

如果一條實鏈只被走過了一部分,那麼它的貢獻是線段樹的深度 ,其中 k 為實鏈的長度

注意這個複雜度只是上界(不然也不會有全域性平衡二叉樹),但已經足夠精細了

我們可以用動態規劃來解這個問題

令dp[u]表示以u為根的子樹中,樹上所有點到根的路徑的複雜度的最大值

乙個根節點u會連出一條實鏈,而這條實鏈上的每個點又會連出若干條虛鏈

令len為實鏈的長度

令w_1, w_2..為實鏈中最深的節點連出的虛子節點,且dp[w_1] >= dp[w_2] >= ..

令v_1, v_2..為實鏈中的其他節點連出的虛子節點,且dp[v_1] >= dp[v_2] >= ..

則dp[u] = max(dp[w_1] + 1, dp[v_1] + lg[len])

這裡lg[len]的值是,之後的分析中也是如此

如果乙個節點v_1不存在,那麼它的dp值就是 0 ,之後的分析中也是如此

我們可以用動態規劃來解這個問題

令dp[u]表示以u為根的子樹中,最優的剖分方案的最壞複雜度

令dp[u][len]表示以u為根的子樹中,實鏈長度為len時,最優的剖分方案的最壞複雜度

令u.ch_1, u.ch_2..為u的子節點,且dp[u.ch_1] >= dp[u.ch_2] >= ..

那麼顯然有

dp[u] = min(dp[u][1], dp[u][2], ..)

dp[u][1] = dp[u.ch_1] + 1,對應於實鏈的長度為 1 時的最優剖分方案

dp[u][2] = max(dp[u.ch_1.ch_1] + 1, dp[u.

ch_2] + 2, dp[u.ch_1.ch_2] + 2),對應於實鏈的長度為 2 時的最優剖分方案

dp[u][3] = max(dp[u.ch_1.ch_1.

ch_1] + 1, max(dp[u.ch_2] , dp[u.ch_1.

ch_2] , dp[u.ch_1.ch_1.

ch2]) + 3),對應於實鏈的長度為 3 時的最優剖分方案

dp[u][k] = max(dp[u(.ch_1)^k] + 1, max(dp[u.ch_2], dp[u.

ch_1.ch_2], dp[u.ch_1.

ch_1.ch2], ..) + lg[k]),對應於實鏈的長度為 k 時的最優剖分方案

也就是說,每次要增長實鏈的時候,都會選擇dp值最大的子節點,這本質上是乙個貪心演算法

觀察dp[u][k] = max(dp[u(.ch_1)^k] + 1, max(dp[u.ch_2], dp[u.

ch_1.ch_2], dp[u.ch_1.

ch_1.ch2], ..) + lg[k])

我們發現隨著k的增加,左邊dp[u(.ch_1)^k] + 1不變或者減一,因為性質dp[u.ch_1] <= dp[u] <= dp[u.ch_1] + 1

我們發現隨著k的增加,右邊max(dp[u.ch_2], dp[u.ch_1.

ch_2], dp[u.ch_1.ch_1.

ch2], ..) + lg[k])不變或者增加

那麼dp[u][k]會在什麼時候取到最小值呢,那必然是在兩個單調函式相交的時候

dp[u(.ch_1)^(k - 1)] + 1 >= max(dp[u.ch_2], dp[u.

ch_1.ch_2], dp[u.ch_1.

ch_1.ch2], ..) + lg[k - 1]

dp[u(.ch_1)^(k + 0)] + 1 >= max(dp[u.ch_2], dp[u.

ch_1.ch_2], dp[u.ch_1.

ch_1.ch2], ..) + lg[k + 0]

dp[u(.ch_1)^(k + 1)] + 1 < max(dp[u.ch_2], dp[u.

ch_1.ch_2], dp[u.ch_1.

ch_1.ch2], ..) + lg[k + 1]

dp[u(.ch_1)^(k + 2)] + 1 < max(dp[u.ch_2], dp[u.

ch_1.ch_2], dp[u.ch_1.

ch_1.ch2], ..) + lg[k + 2]

最終dp[u] = dp[u(.ch_1)^k] + 1

所以我們並不需要計算每乙個dp[u][k],要是要去找到單調函式相交時對應的那個k

我們令tail[u]表示以u為根的子樹的最優剖分中u所在的實鏈中深度最大的節點,即u(.ch_1)^(k - 1)

我們令heap[u]維護max(dp[u.ch_2], dp[u.ch_1.ch_2], dp[u.ch_1.ch_1.ch2], ..)

我們令deep[u]表示節點u在整棵樹中的的深度

那麼有dp[u] = dp[tail[u].ch_1] + 1

那麼有k = deep[u] - deep[tail[u]] + 1

那麼有dp[tail[u].ch_1] + 1 >= heap[u] + lg[deep[u] - deep[tail[u]] + 1]

我們從dp[u.ch_1], tail[u.ch_1], heap[u.

ch_1]著手計算dp[u], tail[u], heap[u],因為tail[u]必然是tail[u.ch_1]本身或其祖先

我們令tail[u] = tail[u.ch_1], heap[u] = heap[u.ch_1],然後把dp[u.ch_2]放到heap[u]裡

如果有dp[tail[u].ch_1] + 1 >= heap[u] + lg[deep[u] - deep[tail[u]] + 1],那麼就得到了正確的值

如果有dp[tail[u].ch_1] + 1 < heap[u] + lg[deep[u] - deep[tail[u]] + 1],那麼正確的值在tail[u]的祖先那裡

我們把dp[tail[u].ch_2]取出heap[u],然後令tail[u] = tail[u].father,迴圈往復,直到得到正確的值,最後算出dp[u]

如果用單調佇列來維護heap[u],時間複雜度為 O(n),非常高效

如果用堆來維護heap[u],時間複雜度為 O(nlgn),也可以接受

對於這個問題,我暫時還沒有得到明確的結果

但是對於很多自稱能卡樹剖的資料(比如OI wiki上的)表現良好

2樓:immortalCO

像這樣根號條根號的鏈構成乙個完全二叉樹,就能卡到 log(sqrt(n))^2=log(n)^2 了(每個點往上有 log 條重鏈,每條重鏈至少 sqrt(n) 長)。(專業卡樹剖)

這樣的資料,不在建線段樹上做文章的演算法都能卡掉。

老闆會反感自己的員工搞副業嗎?

半仙不抽菸 先不說反感,但是內心肯定是不支援的。首先,我們自己作為打工人肯定會覺得,你的工資只買了我日常的8個小時,我剩下的時間如何安排,作為老闆無權過問。這沒錯。但是作為老闆來說呢,你在8小時之外還在做別的副業,是不是就可以說明你花在工作上的時間沒那麼多了。或者換句話說,你會不會在原本該工作的8小...

為什麼自己種的樹,自己不能砍?這是真的嗎?有法律依據嗎? ?

濋薰 不是不能砍,是需要相關手序才能砍。自家的樹就算沒手序砍了,一般人也不會管,就怕被人舉報 農村居民採伐自留地和房前屋後個人所有的零星林木,不需要申辦林木採伐許可證。1 依據 森林法 第三十二條 採伐林木必須申請採伐許可證,按許可證的規定進行採伐 農村居民採伐自留地和房前屋後個人所有的零星林木除外...

舍友天天討論手機, 搞的好像自己很懂似的!?

王二丫 所以,你根本用不著有什麼不舒服的心情。如果有,那就是自己給自己找不愉快。你如果心裡不爽,就盡量不和他產生交流就可以了,做自己想做的事就好。如果沒有辦法避免和他交流,那就戴上面具對待他吧!最後,我想說一句,當你覺得別人的行為不好的時候,說明自己也有行為不好的地方。沒有乙個人是完美的,不是嗎?希...