最近莫名其妙地喜歡上了用這種格式寫各省省選的全套題解= =git
今年浙江省選的出題人是算法競賽界傳說級人物陳立傑,看樣子他的出題風格頗有特色……ABC三題難度是嚴格遞減的,感受若是在作第一題的時候被卡住的話恐怕連想死的心都有了……算法
那麼咱們先從最難的一題開始……= =
數據結構
給定一棵N個結點的有正的邊權、初始點權爲0的無根樹,進行M次操做,每次將一個點u的權值增長e($0 \leq |e| \leq 1000$),保證任意時刻點權非負。你的任務是在每次操做後找到一個帶權重心u,使得全部點到重心的距離與點權的乘積之和最小(即最小化$\sum_{v} dist(u, v) × val_v,並輸出這個最小的值。
ideN, M均不超過${10}^5$.保證每一個點的度數均不超過20.
函數
首先咱們假設每次操做事後咱們能夠快速地在線查詢以任意一個點爲關鍵點獲得的權值和,那麼在這種狀況下如何求出最小權值?
ui
爲了表達方便,咱們不妨設當前以點u爲關鍵點求得的權值和爲$S_u$,那麼咱們不難發現這樣一個性質:在樹上任意兩點a, b之間的路徑上,$S_u$構成了一個存在極小值的單峯函數。證實也很簡單:考慮路徑上任意一條邊e,設e兩端點分別爲s, t,兩端鏈接的點集分別爲S, T,邊權爲e.v。則關鍵點從s走到t的過程當中權值和的變化量:$$\Delta = S_t - S_s = (\sum_{u \in S} val_u - \sum_{v \in T} val_v) * e.v.$$ 而在轉移的過程當中,點t和它的不在鏈上的後代結點都將從T集合轉移到S集合,即 $(\sum_{u \in S} val_u - \sum_{v \in T} val_v)$ 是單調遞增的,又由題意得知邊權都是正整數,所以函數 $\Delta = S_t - S_s = (\sum_{t \in S} val_u- \sum_{v \in T} val_v) * e.v.$ 的零點區間必定惟一(因爲$\Delta$是離散函數,這裏「零點區間」指的是左右兩側函數值正負性相反的區間),且左負右正。因爲$\Delta$表示的是S函數的增量,那麼$\Delta$的零點區間惟一且左負右正就證實了S是存在極小值的單峯函數。
this
那麼咱們設點c爲咱們要求的一個帶權重心。考慮樹上任意一點u和它到c之間的路徑,因爲u的S函數取最小值,又由路徑上S函數值的單峯性,咱們能夠證實在從u到c的路徑上S值是單調遞增的,而相鄰兩點S值相同當且僅當這兩點的S值均爲$S_u$,即最小值。最後這點結論能夠由「零點區間連續」天然地得出。
spa
有了這條性質,查詢最小權值就好辦了。咱們能夠在樹上任取一點u將樹有根化,判斷它的各鄰接點的S值是否小於$S_u$。若存在一點v使得$S_v < S_u$,那麼根據上面的結論,咱們知道答案必定在v所在的子樹中,遞歸查詢便可。若不存在這樣的點v,那麼答案必定是$S_u$。
code
聽起來很爽對不對?然而,若是咱們每次在樹上「任取一點」,最壞狀況下遞歸的深度能夠達到$O(N)$級別,時間複雜度退化得很嚴重。怎麼辦呢?咱們能夠在樹上找到一點u,使得以u爲根最大的子樹的規模最小化(通常稱u爲這棵樹的重心)。那麼這樣每棵子樹的規模都不會超過原樹規模的1/2,那麼不難證實此時遞歸查詢的深度就成了$O(\log N)$。
blog
再來考慮開頭咱們假設的咱們已經會了的操做——在線查詢任意一個$S_u$。
考慮咱們剛纔創建的重心分治結構。對點v進行修改時,咱們能夠花費$O(\log N)$的時間更新v所在的每一層分治結構的重心維護的答案(即在分治u維護的答案中增長$dist(u, v) * \Delta val_v$),並記錄每層分治結構中的結點對上一層分治維護的答案的貢獻。在對點v查詢時,先將答案設爲v分治中維護的答案,而後向上移動累加答案:在從分治current向它的上一層分治parent移動時,在parent維護的答案中減去current對它的貢獻獲得$\delta S$,將獲得的結果臨時當作點v的後代累加進答案。即$Ans = lastAns + \delta S + (Sum_{parent} - Sum_{current}) * dist(parent, v) $,其中$Sum_t$表示t維護的分治結構中全部點權的平凡加和。這樣,咱們就會作這道題了。
若是咱們用倍增LCA法求dist,時間複雜度爲$O((N+M) \log^3 N) $,可能有些卡常數。考慮到操做不會改變原樹的結構,咱們能夠在$O(N \log N)$的時間內預處理後經過ST表維護DFS序列來求LCA,總時間複雜度$O((N+M) \log^2 N)$.
給定一個n個點m條邊的無向圖,每條邊的權值在0~1之間隨機選取,求這張圖的最小瓶頸生成樹的瓶頸的指望值。
點數不超過10, 保證無重邊且無自環。
因爲題目中的最小瓶頸生成樹的瓶頸大小是連續變量,咱們沒法經過簡單地枚舉答案和機率來求解。不妨這樣考慮:設$F_S(x)$表示圖中全部小於x的邊能使點集S連通的機率。那麼點集S的最小瓶頸爲x的機率就是$$P_{(ans=x)} = \lim_{\Delta x \to 0} F_S(x+\Delta x) - F_S(x)$$也就是$$P_{(ans=x)} = F_S '(x) \mathrm{d} x$$
由指望的定義,咱們有:$$E = \int_0^1 x * F_S ' (x) \mathrm{d} x$$是個乘積複合函數,咱們對它作分部積分:$$E = \left. \left( x \int F_S '(x) \mathrm{d} x - \int (x' \int F_S '(x) \mathrm{d} x) \right) \right|_0^1 $$獲得:$$E = \left. \left( x F_S(x) - \int F_S(x) \mathrm{d} x \right) \right|_0^1$$那麼$$E = 1 - \left. \int F_S(x) \mathrm{d} x \right|_0^1$$
那麼咱們只須要用dp求出整個圖的F_V函數,再積分一下就能夠獲得答案了。
點集連通的機率彷佛無法直接求?那麼咱們來考慮相反的狀況,點集S不連通的機率。咱們能夠任選一點$v_0$,枚舉它所在的連通塊S',並計算出S'與$S - S'$的割邊數量cnt,那麼$$F_S = 1 - \sum_{S' \ni v_0 \land S' \subsetneqq S} (1 - x) ^ {cnt} $$這樣就能夠求出答案了。
給定一棵N個結點的樹,每一個結點有一個顏色,求樹上的全部路徑通過的不一樣顏色序列的數量。
N不超過100000,保證樹上的葉子結點數量不超過20,顏色值不超過10.
一道比較良心的題……保證了葉子結點不超過20個,咱們就能夠枚舉全部的葉子,分別遍歷一遍整棵樹,對獲得的全部序列創建多串後綴數據結構,查詢不一樣的子串數便可。用廣義SAM實現起來比較容易。