超級Trick Kruskal重構樹學習筆記

2021-10-14 03:57:44 字數 2473 閱讀 4042

例題例2

在讀這篇文章之前,請確保你會kruskal(最小生成樹)演算法與樹上lca演算法。

給定一棵樹,邊帶權,每次查詢兩點間經過的所有邊的長度的最小值。

雖然本題可以採用時間複雜度優秀的樹剖+rmq或樹上倍增,但是本題也可以採用kruskal重構樹的方法解決

首先,我們將樹上的邊按照權值從小到大排序。考慮建立出一棵新樹:

從前往後掃一遍邊。假設當前掃到的邊連線了節點 u,v

u,vu,

v 且邊權 w

ww。若加入u,v

u,vu,

v這條邊後不會出現環(即為最小生成樹的樹邊),那麼我們就建立乙個新點p

pp,將p

pp 分別連向 u,v

u,vu,

v 所在集合的代表,並令點 p

pp 的權值為 w

ww ;最後我們將 u,v

u,vu,

v 所在集合的代表連向 p

pp 。並查集維護即可。

建立出來的這棵樹被稱為"kruskal重構樹"。它有乙個重要的性質

\lfloor

⌊ 這棵樹是乙個二叉樹;更進一步的,也是乙個大根堆/小根堆

\rceil

⌉ 因此,對於一次形如 (x,

y)(x,y)

(x,y

) 的詢問,答案為新樹上 lca(x

,y)\text(x,y)

lca(x,

y)的點權。

時間複雜度 o(n

9首先我們建立出這個圖的kruskal重構樹。

不難發現,一次詢問中所有滿足要求的點均在以 r

rr 為根的子樹中。r

rr 可以通過倍增求出。

於是現在問題變為:靜態查詢子樹中的點權第 k

kk 小值。這顯然可以使用 dfs 序+主席樹維護,

注意 h

hh 需要離散化。時間複雜度為o((

n+m)

log⁡n)

o((n+m) \log n)

o((n+m

)logn)

。[noi2018 d1t1]歸程

給定一棵大小為n

nn的無向圖。你需要執行q

qq次詢問或操作:

1 u: 令所有與u

uu連通的節點中點權最大的節點是v

vv,你需要將v

vv的點權變為0

00並輸出vvv;

2 x y: 刪除從x

xx到y

yy的無向邊。保證這條邊存在。

n ,q

≤5×1

05n,q \le 5 \times 10^5

n,q≤5×

105,時限 2s

\text

2s。動態刪邊,動態查詢點權的最大值……我們自然而然地想到了lct。可惜這個東西的常數非常大;換句話說,這個東西的時間複雜度並不正確。我們需要一種常數較小的單 log

⁡\log

log 做法。

考慮給每條邊乙個權值,表示它被刪除的時刻。特別的,永遠沒有被刪除的邊的權值為 ∞

∞∞ 。於是,第 i

ii 次詢問就變為了「查詢僅經過權值不小於 i

ii 的邊所能到達的最小點權」。

我們建出 kruskal 重構樹,此時問題變為:單點修改,查詢子樹最小值位置。我們建立一棵線段樹,每個節點維護其對應區間的點權最大值點權最大值的位置

時間複雜度o((

n+m)

log⁡m)

o((n+m) \log m)

o((n+m

)logm)

hdu1226 超級密碼(bfs 餘數判重)

problem description ignatius花了乙個星期的時間終於找到了傳說中的寶藏,寶藏被放在乙個房間裡,房間的門用密碼鎖起來了,在門旁邊的牆上有一些關於密碼的提示資訊 密碼是乙個c進製的數,並且只能由給定的m個數字構成,同時密碼是乙個給定十進位制整數n 0 n 5000 的正整數倍 ...

超級簡單的方法實現去重與排序

程式設計題 字串中字元排序 問題描述 編寫乙個程式,從鍵盤接收乙個字串,然後按照字元順序從小到大進行排序,並刪除重複的字元。輸入形式 使用者在第一行輸入乙個字串。輸出形式 程式按照字元 ascii 順序從小到大排序字串,並刪除重複的字元進行輸出。樣例輸入 badacgegfacb 樣例輸出 abcd...

大檔案的排序和去重 超級簡單的實現

有一道校招生的面試題,是要給乙個很大的檔案 不能全部放記憶體,比如1t 按行來排序和去重。一種簡單解決方案就是分而治之,先打大檔案分詞大小均勻的若干個小檔案,然後對小檔案排好序,最後再merge所有的小檔案,在merge的過程中去掉重複的內容。在 linux下實現這個邏輯甚至不用自己寫 只要用she...