點分治 動態點分治

2022-02-06 16:26:48 字數 1239 閱讀 6427

實在拖得太久了。

先扔掉資料

分治的核心是盡量把乙個整體分成接近的兩個部分,這樣遞迴處理可以讓複雜度從n²變成nlogn。

兩個問題,如何區分和如何算答案。

對於第乙個問題,重心,然後就是找重心的方法,兩個dfs,

對於第二個問題,對於每個重心算當前塊中每個點到重心的答案,然後由重心分開的塊要把多餘的資訊去掉。

求出重心的兩個dfs

第一,先算出每個點的子樹大小

void dfs_size(int x,int

fa) }

}

第二,如果把乙個點作為重心,它會把當前的聯通塊分成兩個部分,子樹和整個聯通段的大小-子樹,通過第二個dfs找到乙個可以把圖分成兩快大小平衡的連通圖

void dfs_find(int x,int fa,int

y) }

if (msz[root]>msz[x]) root=x;

}

//這裡把root開成全域性變數

統計答案的more函式和dfs下去的calc函式

more函式用於計算答案,當需要維護動態資訊是,more函式用於一開始構建節點儲存資料結構的初始化。

ll more(int x,int

len)

//update

calc函式用於不斷遞迴下去就子樹

void calc(int

x) }

}

如果子樹的資訊無法通過more直接減掉,可以分開寫calc和more

,即

void calc(int

x) }

repedge(i,root)

}

附上點分治會用上的dfs_len函式,用於記錄長度資訊

void dfs_len(int x,int fa,int

len)

}

對於動態點分治,也是由點分治引出來的,顯然對於乙個點,他最多屬於logn個重心所在的塊,重心之間又是有層次關係,可以抽象構造乙個重心樹,用資料結構就可以啦。

比較麻煩的在於對於重心帶的資料結構,他的域要控制得和這個塊大小差不多,很多人用vec動態申請空間當bit用,我習慣用線段樹。

難點跟點分治一樣,在於剔除在同一棵子樹上的重複資訊,所以要構建兩個資料結構,乙個做加的,乙個做減的

構建完後,對於詢問或修改的某個點,依次訪問它從裡到外每個重心的統計資訊。

點分治與動態點分治

點分治一般是用於解決樹上路徑問題。樹的重心 把重心這個點割掉後,使所形成的最大的聯通塊大小最小的點。可以證明重心子樹的大小最大不會超過 n over 2 重心可以通過 dfs 一遍求出。maxsiz x 表示割掉點x後所形成的的最大的聯通塊的大小 void dfs int x,int fa max ...

動態點分治

由於蒟蒻太遜,現在才開始學動態點分治,寫乙個 blog 吧。動態點分治是利用點分治的過程,建成一顆由子樹重心連線而成的點分樹,這棵樹的高度為 log n 級別的,因此可以通過暴力跳父親完成修改操作。建立點分樹的過程,就是按照點分治的流程,記錄上級重心並連線,即可獲得一棵點分樹。點分樹的結構與原樹不相...

動態點分治

首先你要先會點分治,然後動態點分治就是把點分治可持久化一下,讓其不用再每次詢問時都重新做一遍 具體就是,你考慮做點分的時候,你在每個分治重心上統計它所管轄的所有點的資訊,並計算答案。那麼每個點的資訊只會出現在它上面的分治重心中,所以我們把每層分治重心向上一層的連邊,這樣每個點的資訊只會出現都在它所有...