點分治(樹分治)

2022-05-05 12:33:14 字數 2939 閱讀 9441

將原問題分解成若干相同形式,相互獨立的子問題,各個擊破

一般用來解決有關樹上路徑的統計和詢問

p4178 tree

給定一棵 n 個節點的樹,每條邊有邊權,求出樹上兩點距離小於等於 k 的點對數量。

暴力做法;(o(n2))

點分治做法:

選擇乙個點作為分治中心,令其為rt做dfs。對於一條路徑path(u,v),其要麼經過rt(即lca(u,v) = = rt),要麼在某個子樹sub(son[rt])中

把問題形式化為:

solve

(t,rt)

= 統計t樹中經過rt且長度<=k的路徑數量

對t數進行分治work(t)的步驟:

1.找到乙個分治中心rt

2.ans+=solve(t,rt)//統計答案(統計所有穿過化的路徑)

3.對所有rt的子節點v,遞迴呼叫work(v)

int

work

(u)

所有合法路徑在上述分治過程中被不重不漏地統計到

詳細過程:

假設高度一共有h層,經過h層遞迴後到達邊界,每一層子問題互不重疊,

每一層都是o(n)

總複雜度:o(h*n)

我們控制h的大小

(h = 遞迴的層數)

點分治的複雜度被以下兩個條件保證:

1.h=o(log n),每次選t的重心作為rt(重心滿足刪除後形成的子樹大小為之前一半)

2.找重心以及統計答案solve(t,rt)的複雜度=o(size(t)),或者帶log,不與n相關

條件1保證每遞迴一層size(t)減半,log層到達邊界

條件2保證每層複雜度為o(n)或者o(nlog n)

點分治總複雜度o(log n )或o(nlog2n),取決於solve是否帶log。

題目描述

給定一棵有 n 個點的樹,詢問樹上距離為 k 的點對是否存在。

//niiick

#include

#include

#include

#include

#include

#include

using

namespace std;

intread()

while

(ss>=

'0'&&ss<=

'9')

return f*x;

}const

int inf=

10000000

;const

int maxn=

100010

;int n,m;

struct nodee[maxn<<1]

;int tot,head[maxn]

;int maxp[maxn]

,size[maxn]

,dis[maxn]

,rem[maxn]

;int vis[maxn]

,test[inf]

,judge[inf]

,q[maxn]

;int query[

1010];

int sum,rt;

int ans;

void

add(

int u,

int v,

int dis)

void

getrt

(int u,

int pa)

//求重心

maxp[u]

=max

(maxp[u]

,sum-size[u]);

if(maxp[u]

) rt=u;

}void

getdis

(int u,

int fa)

//每乙個子節點到根的距離

}void

calc

(int u)

for(

int j=rem[0]

;j;--j)

//儲存出現過的dis於judge

}for

(int i=

1;i<=p;

++i)

//處理完這個子樹就清空judge

judge[q[i]]=

0;//特別注意一定不要用memeset,會t

}void

solve

(int u)

}int

main()

for(

int i=

1;i<=m;

++i)

query[i]

=read()

;//先記錄每個詢問以離線處理

maxp[rt]

=sum=n;

//第一次先找整棵樹的重心

getrt(1

,0);

solve

(rt)

;//對樹進行點分治

for(

int i=

1;i<=m;

++i)

return0;

}

Tree(樹分治 點分治)

原題 poj 1741 題意 有一棵n個節點的樹,每條邊都有乙個權值,問有多少個節點之間的距離小於等於k,解析 典型的樹分治,對於每一棵樹,我們首先找到它的重心 重心 一棵樹中以這個點為root時的最大子樹的節點數最小 int siz n maxn n 這棵子樹大小,最大子樹大小 void getg...

點分治 動態點分治

實在拖得太久了。先扔掉資料 分治的核心是盡量把乙個整體分成接近的兩個部分,這樣遞迴處理可以讓複雜度從n 變成nlogn。兩個問題,如何區分和如何算答案。對於第乙個問題,重心,然後就是找重心的方法,兩個dfs,對於第二個問題,對於每個重心算當前塊中每個點到重心的答案,然後由重心分開的塊要把多餘的資訊去...

樹的點分治

codeforces 150e 通過點分治以及合併子樹檢查二分的答案 用深度從小到大的方式可以剪枝,達到nlog 2 n 的複雜度 不離散化常數巨大,離散化常數依然巨大 include include include include include define maxn 100005 define...