點分治 理解及例題

2022-05-20 00:57:45 字數 2132 閱讀 2989

點分治,基於點的分治,處理一些路徑計數問題;

其思路為:

子樹結構:子樹結構雖然的確是某點的乙個子樹,但我們討論點分治時,相當於把這個子樹摘下來,當做無根樹處理;

對於乙個子樹結構:

處理子樹結構中與某個單點(未必是原根)相關的路徑;

以這個被處理的點為新根,找出她的子樹,變成遞迴下一層要處理的子樹結構;

遞迴下一層;

點分治為什麼可以求解諸如"統計所有合乎某一規範的路徑的相關資訊"之類的問題呢?

其原因在於此類問題可以通過分治解決:

對於一棵無根樹的所有路徑;

可以分為經過某個單點的和不經過某個單點的兩類;

統計經過這一點的路徑後,

剩下其他的路徑都可看做是以這一點為根後,根的所有子樹各自內部的路徑;

也可看做把這一點摘去後得到的森林中每個樹內部的路徑;

然後重複這一過程即可解決統計所有合乎某一規範的路徑的相關資訊;

因此點分治問題的要點是尋找一種可以統計經過某一點的路徑資訊的優秀演算法

在乙個常見的,約定俗成的寫法下(就是乙個「說點分治就是指她」的寫法)

點分治時間複雜度可以達到o(logn*f(num(1))

(num(i)為處理第i個單點時的資料範圍);

(f(i)為處理資料範圍為i的單點的時間複雜度);

(條件是f(i)是線性的);

這個複雜度是因為:

在遞迴分治的過程中,

對於每層,其num(i)之和與num(1)是同級的,

由於f(i)(往往)是線性的,故可以認為每層的各點的f(i)之和與f(num(1))同級,

在此基礎上,我們使用裡一種巧妙的辦法,使得分治層數不超過logn層;

於是達到了需要的效率;

所以這個神奇的方法是什麼呢?

由於對於每個子樹結構,我們要處理的那個單點並沒有什麼特殊要求

於是考慮通過限定處理哪個單點以提高效率;

處理哪個單點會影響效率麼?

會的;處理不同的單點會導致下一層的那些子樹結構大小不同;

理想狀態下我們希望;

不管下一層有多少個子樹結構,每乙個子樹結構的大小都盡量小,因為這樣可以是分治層數盡量少

(比如,當我們遇到菊花圖時,如果第一次處理的是該樹中間的那個點,那麼儘管下一層要處理n-1個點,但是下一層每個子樹結構的大小都只有1,這就意味著不用繼續分治了,只分治了兩層)

考慮把每層的子樹大小的最大數量級,都變成上一層的一半;

這樣就能使分治層數不超過logn時就不能再分了(因為連最大的那個子樹此時的大小也是1了);

如何做到這點呢?

首先定義子樹結構的重心:

在點分治中若在本層處理點i,可以使下一層處理的最大子樹的節點最少,則點i為該子樹結構的重心;

可以看出重心的節點最多的子樹的節點數不會超過原子樹結構的一半;

證明:若重心的節點最多的子樹的節點數超過了原子樹結構的一半;

那麼你看看以她的這個子樹的根取代她作為重心的情況;

發現反而更有重心的樣子;

於是這個重心不是重心;

所以重心的節點最多的子樹的節點數不會超過原子樹結構的一半;

於是我們用現在得到的方法重新修訂、精細點分治的流程:

對於乙個子樹結構:

處理與子樹結構中重心相關;

以重心為新根,找出她的子樹,變成遞迴下一層要處理的子樹結構;

遞迴下一層;

這就是乙個常規的約定俗成的卻又效率優秀的點分治啦;

然後是一些實現:

分治的主體可以由dfs實現,

但跳轉時,不會是直接跳到當前點的子節點,而是跳到當前點的子樹重心上;

求重心:

兩遍dfs實現:

inline void dfs_size(int now,int

fa)}

inline

int dfs_root(int now,int fa,int

r)

if(max_size[now]1

) root=now;

return

root;

}

分治部分:

void part_dfs(int

now)

}

具體見例題

例題:poj p1741 tree

題解

點分治模板理解

點分治 模擬序列分治。n 2列舉 掃了很多重複部分。分治 共用重複部分,減少資訊收集冗餘。log思想進行劃分。單次操作 序列分治 中間點。點分治 樹上的節點。點分治不僅要減少資訊收集冗餘,還要減少同一資訊處理次數。例如對乙個點,不分治會掃n次,分治是log次。就是一條鏈 繩,從頭到尾剪,不如從中間剪...

點分治及題目

一般可以用於處理大規模樹上路徑問題 既然是處理路徑問題,那麼可以把路徑分成兩種,經過當前根節點的路徑,不經過當前根節點的路徑 處理完經過當前根節點的路徑,然後刪掉根節點,此時肯定會形成乙個或多個子樹,那麼剩下的不經過當前根節點的路徑,遞迴到這些子樹中處理 刪掉的節點肯定在接下來的處理中就不會被考慮了...

點分治模板 (例題 樹中點對距離) 待更新 坑

description 給出一棵帶邊權的樹,問有多少對點的距離 len c表示最大兒子的節點的size size表示子樹大小 處理子樹大小 void get size int x,int y 找重心 size r size x 是x上面部分的樹的尺寸,跟x的最大孩子比,找到最大孩子的最小差值節點 v...