例題例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)
logn)
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)
logm)
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...