JZOJ5966【NOIP2018提高組D2T3】保衛王國(並查集)
題目
還是懶得把題目放上來了。
大意:給你一棵帶點權的樹,你要花費一些代價選擇一些點使得相鄰的兩個點至少有一個被選。
然後有很多個詢問,每個詢問強制兩個點的狀態,問強制了這兩個點的狀態後的方案。
比賽思路
沒時間了,沒時間了……
匆匆打個44分的暴力就好了。
結果混淆了概念,打出來的DP是求一個點自己或周圍至少有一個選的方案,和題目就不是一個樣子。
比賽結束了,我還沒有調處來,然後就爆0了。
解法
先說說暴力。
這是一個非常典型的問題,設
表示以
為根的子樹中,不選或選
的最優解。
(比賽時設的根本就不是同一道題)
這個DP的方程應該沒有人不懂的吧:
所以,暴力做法就是,將某一個值賦值為無限大,然後暴力地重新DP(當然,其實只需要更新它自己到根的這條路徑就好了)。
考慮正解。
首先說一下,我的解法是在JZOJ、洛谷排名第一的並查集解法,時間複雜度幾乎是線性的。倍增解法或許和並查集解法有很大相似之處,而對於那些打樹鏈剖分的動態DP的方法,個人認為我的方法和他們的方法存在著太大的差別。
首先我們可以抽象地思考一下:
對於這個詢問,其實就是將詢問的兩個點提起來,答案為限制了它們之後,鏈上的子樹的貢獻。
首先我們處理另一個DP,設
表示除以
為根的子樹外,不選或選
的最優解。(將它提起來之後,之前的父親也可以看成一個兒子。)
這個方程也是挺好想的(為了方便表達,設
):
這個方程是從上往下轉移的。
其中
中,由
的轉移方程得
下面的那個類似。
這樣子DP部分就搞完了,剩下的東西就是維護。
我們可以參考一下Tarjan求LCA的過程(這個名字有毒,和強聯通分量的那個完全不是一個東西,不要被名字震撼到),其實也就是用並查集求LCA的過程。
簡要地說一下過程:
對於一個節點
,首先
,然後dfs它的兒子。當從它的兒子那裡回溯上來的時候,
,然後列舉和
有關聯的詢問,設另一個點為
,如果
,則它還未被訪問過,先不理它;否則,
就是
。
至於這個演算法是為什麼,其實隨便想一想就可以了。在dfs的時候,先到
,再到
,回溯上去,在
處轉彎,再走到
。由此可見,自
到
,深度最小的地方就是它們的
(莫名其妙地想起了ST表求LCA),深度最小的地方也就是
在並查集上的最遠祖先。
對於每個點,我們不只是記錄一下它在並查集上的父親,還要記錄一下它和他父親之間的答案。
每個節點的答案記錄
條資訊,表示父親