1. 程式人生 > >樹鏈剖分的一種用法

樹鏈剖分的一種用法

我們 祖先 單點 數組 樹狀數組 實現 修改 相加 比較

這篇文章好像發得有點遲了啊QAQ之前忘了發了

又好久沒更了,講一個提高組內容。

我們來考慮一個有趣的問題,我們有一棵有根樹,每個點有點權,要求支持單點加,子樹加。

詢問比較奇怪,每個點有一個點權x,假裝不變,每次詢問指定一個點p,對於它的每個孩子(直系的)s,將x[s]*s的子樹和相加輸出。

先假裝沒有子樹加,考慮直接用樹鏈剖分來做這個東西。那麽我們詢問某個點的孩子的時候,我們發現有兩種孩子,一種是重孩子,一種是輕孩子。

對於重孩子,因為只有一個,所以我們可以直接在dfs序上搞一個樹狀數組統計。

如果是輕孩子?考慮一個被計入答案的點,那麽這個輕孩子肯定是這個點的祖先,而且是某條重鏈的頂端。我們可以在單點加的時候暴力跳它往上的重鏈,跳到某重鏈頂端時更新頂端的父親的答案,然後繼續跳。考慮到重鏈剖分的復雜度,這樣做是一個log的。

接下來我們考慮子樹加怎麽做。假設我們詢問a的子樹,子樹b之前進行了一次子樹加。如果a和b子樹不交顯然對答案沒有影響。如果a是b的祖先(不包括b),那麽我們可以把b整棵子樹當成一個點,像上面那樣跳重鏈更新答案。如果b是a的祖先(包括a),那麽a子樹的每個點都受到了影響,我們只要把a的輕兒子的x相加乘上計入貢獻即可,這個可以用兩遍dfs序來實現。

用類似的方法可以支持點權修改和詢問子樹dp值。如果dp值比較復雜,還可以考慮使用線段樹維護每個點的子樹。

樹鏈剖分的一種用法