樹上差分,顧名思義,就是在樹上進行差分,以起到優化復雜度的目的。主要作用是對樹上的路徑進行修改和查詢操作,在修改多、查詢少的情況下復雜度比較優秀。實際上,樹上差分能夠實現的操作,用線段樹、樹剖、$LCT$等等也可以實現,但它的優勢在於實現簡單,可以避免在考場上出現寫題五分鍾、調試兩小時的情況 當然大佬可以忽略這點
差分
在講解樹上差分之前,先講一下差分的思想。
差分,可以當做前綴和的逆運算。既然是逆運算,運算方法自然就是相反的了。定義差分數組$diff$,則運算法則為:(設原數列為$a$)
$$diff_i=a_i-a_{i-1}$$
作個比較:
原數列 | 9 | 4 | 7 | 5 | 9 |
---|---|---|---|---|---|
前綴和 | 9 | 13 | 20 | 25 | 34 |
差分數組 | 9 | -5 | 3 | -2 | 4 |
前綴和的差分數組 | 9 | 4 | 7 | 5 | 9 |
差分數組的前綴和 | 9 | 4 | 7 | 5 | 9 |
顯然,原數列的前綴和的差分數組還是原數列,原數列的差分數組的前綴和也是原數列,這就是差分被稱為前綴和的逆運算的原因,也是差分可以用來優化操作的原因。實際上,差分優化和前綴和優化原理類似,只是實現相反。前綴和優化常常對前綴和數組作差,差分優化也常常對差分數組求前綴和。
這樣,差分的概念就很清晰了。接下來開始進入正題。
樹上差分
樹上差分有什么作用?舉個例子,如果題目要求對樹上的一段路徑進行操作,並詢問某個點或某條邊被經過的次數,樹上差分就可以派上用場了。這就是樹上差分的基本操作。
樹上差分,就是利用差分的性質,對路徑上的重要節點進行修改(而不是暴力全改),作為其差分數組的值,最后在求值時,利用$dfs$遍歷求出差分數組的前綴和,就可以達到降低復雜度的目的。
樹上差分時需要求$LCA$,不會的可以點擊食用。
點差分
設將兩點$u,v$之間路徑上的所有點權增加$x$,$o=LCA(u,v)$,$o$的父親節點為$p$,則操作如下:
diff[u]+=x,diff[v]+=x,diff[o]-=x,diff[p]-=x;
怎么樣,是不是很簡單!原理也很簡單,舉個例子:
設原樹如下,現要將$2,3$之間路徑上的所有點的權值增加$3$,設原權值均為$0$。
則操作后有:
這樣,只要$dfs$一遍,遍歷時統計以每個節點為根的樹的節點的權值和,就是當前節點的最終權值! 是不是很厲害
就是差分的思想,這里就不多說了。
邊差分
思想一樣,講一下操作。
設將兩點$u,v$之間路徑上的所有邊權增加$x$,$o=LCA(u,v)$,以每條邊兩端深度較大的節點存儲該邊的差分數組,則操作如下:
diff[u]+=x,diff[v]+=x,diff[o]-=2*x;
再舉個例子,還是上面那個圖 絕對不是我懶
則操作后有:
同樣地,只要$dfs$一遍,遍歷時統計以每個節點為根的樹的節點的權值和,就是當前節點到父親節點的邊的最終權值了!
是不是很厲害
至於為什么點差分和邊差分的操作不一樣,很簡單,請讀者自己思考。
樹上差分主要還是學習思想吧!
習題:
差分
綜合應用題:P1083
樹上差分
簡單模板題:P3128
綜合應用題:P2680
參考資料:
2019.7.16 於廈門外國語學校石獅分校