點分治一般是用來解決樹上路徑統計的問題, 而動態點分治(也稱點分樹),是用資料結構樹上路徑資訊。
首先顯然的\(\theta (n^2 \log n)\)的列舉演算法
for (int i = 1; i <= n; i ++ )
}
比較難優化,我們可以換一種考慮方式。
以\(p\)為樹根, 則對\(p\)而言, 樹上的路徑可以分為兩種
1.經過\(p\)的路徑
2.不經過\(p\)的路徑(包含於\(p\)的某個子樹中)
第\(2\)種情況我們可以遞迴(以子樹的根再進行計算)
void solve (int u)
}
這樣最劣時間複雜度仍為\(\theta(n^2 \log n)\) 鏈既可以卡掉
如果遞迴到\(t\)層,那麼時間複雜度為\(\theta (tn\log n)\)
如何讓\(t\)盡可能的小,我們可以每次選擇樹的重心作為根節點\(p\),容易證明點分治至多遞迴\(\log n\)層,時間複雜度也優化到了\(\theta (n \log ^ 2n)\)
點分治的過程為\(4\)步
1.選當前子樹的重心\(p\)作為根節點
2.從\(p\)出發進行一次\(dfs\),求出對應資訊
3.執行\(solve(p)\)
4.標記\(p\),遞迴執行\(p\)的每棵子樹
** code
逆元預處理即可
用樹狀陣列維護資訊(細節:樹狀陣列不能出現\(0\),所以集體向右偏轉\(1\))
首先我們回憶一下點分治的過程,對於當前重心,他管轄的是經過他的路徑,那麼我們考慮修改乙個點,那麼有至多有\(\log n\)個重心路徑受影響,我們可以用資料結構來維護相關資訊,即可在\(\log ^2 n\)的時間解決。
對於每乙個點,我們可以開一顆權值樹狀陣列\(/\)權值線段樹來維護,由於空間開不下所以常常要用動態開點線段樹。維護經過當前點距離為\(s\)的點權之和。
我們可以在處理重心的時候檢出乙個點分樹,及兩兩重心相連(不用建出來,只要建立上一層的重心即可)。
inline void insert (int rt, int id, int u, int f)
}inline void solve (int u)
}
我們查詢距離\(u\)點距離\(\leq k\)的路徑
ans += query (rt[u], 0, n, k);
for (int i = u; fa[i]; i = fa[i])
但這樣我們發現有問題,因為有些路徑重複算了,我們要減去子樹的影響。
ans += query (rt[u][0], 0, n, k);
for (int i = u; fa[i]; i = fa[i])
return ans;
同理修改也可以得出。
** code
Python全棧 第九課 學習筆記
函式的結構與呼叫 函式什麼時候執行?函式的返回值 s1 fsjkdafshdjfsdhafjksda l1 1,2,3,4,5,6 def my len s count 0 for i in s count 1 print count my len s1 my len l1 return 在函式中遇...
python基礎第九課筆記和作業
用函式實現乙個判斷使用者輸入的年份是否是閏年的程式 def runnian years if years 4 0and years 100 0 or years 400 0 print years,是閏年 else print years,不是閏年 runnian 2021 猴子吃桃問題 遞迴 猴子...
Python學習第九課 匿名函式
匿名函式 func lambda x x 1 x表示引數 x 1表示處理邏輯 print func 10 輸出結果為11 例 如何將name hanhan 改為 hanhan shuai的形式 普通函式寫法 name hanhan def change name x return name shua...