點分治詳解

2021-10-02 06:05:35 字數 2732 閱讀 5400

今天做了一道點分治的題目,所以就去網上學了一下。

相信大家都聽說過「分治」吧,分治就是「分而治之」一般是把n分成2份,然後再對每乙份進行相同的操作,最後合併起來。

而點分治,一般情況下是在一棵樹上面進行分治,和普通的分治大同小異。

先看一道例題

【題意】

給定乙個有n個點(編號1,2,…,n)的樹,每條邊都有乙個權值(不超過1000)。

樹上兩個節點x與y之間的路徑長度就是路徑上各條邊的權值之和。

求長度不超過k的路徑有多少條。

poj 1741 – tree

【輸入格式】

輸入包含多組測試樣例。

每組測試樣例的第一行包含兩個正整數n和k。

接下來n-1行,每行包含三個正整數u,v,l,表示節點u與v之間存在一條邊,且邊的權值為l。

當輸入樣例n=0,k=0時,表示輸入終止,且該樣例無需處理。

【輸出格式】

每個測試樣例輸出乙個結果。

每個結果佔一行。

【資料範圍】

n≤10000,k≤10^7

【輸入樣例】

5 41 2 3

1 3 1

1 4 2

3 5 1

0 0【輸出樣例】

8先是考慮暴力的解法,直接列舉每乙個點,求lca,然後判斷是否<=k,可以得10分

仔細想想,對於乙個點來說,長度<=k的路徑無非就只有兩種:

1.經過該點

2.不經過該點

所以我們採取點分治的做法,先選1作為根節點,求出經過1且<=k的路徑條數,然後刪掉1,再對1的每個兒子進行重複操作

那麼我們怎麼求出路徑的條數呢

設d[i]為i到根節點root的距離,其中d[root]=0

搜尋求出d,對d從小到大排序

然後我們令指標l = 1, r = tp (tp為d中,點的個數)

如果 d[l] + d[r] <= k ,結果就加上r-l+1,然後l++

否則r- -

但是這樣會出現乙個問題,比如son是root的乙個兒子,在son的子樹中,有很多個加起來滿足<=k的,而這些都不經過u,怎麼辦???

容斥原理!!!

對於每個兒子,令它的d不變,統計一次<=k的個數,從ans裡面減去這個數就好了。

這樣可以取得70分

為什麼只有70呢

舉個例子吧,如果樹退化成鏈的話,這個做法就和暴力沒有區別,時間複雜度o(n

2log

n)o(n^2logn)

o(n2lo

gn)怎麼辦呢,因為這是一棵無根樹,每乙個點成為根節點都不會影響結果,所以我們每次都從當前的樹種求出它的重心作為root,這樣的話,無論樹怎麼樣,都只有log

nlogn

logn

層,時間複雜度o(n

這是形象的搜尋過程

參考**

#include

#include

#include

using

namespace std;

const

int n =

10006

;int n, m, k, all, ans, root;

//m是為了好看,all表示當前的樹中節點總數,root表示根節點

int tot, head[n]

, ver[n<<1]

, leng[n<<1]

, next[n<<1]

;//儲存邊

int max_part[n]

, size[n]

, d[n]

;//max_part[i]表示刪去i以後剩餘的最大部分,size表示子樹大小,d表示到根節點的距離

int tp, sta[n]

;//儲存每個點到根節點的距離

bool vis[n]

;//判斷這個點是否做過做過根節點(是否被刪除)

void

add(

int u,

int v,

int w)

void

dfs1

(int u,

int fa)

max_part[u]

=max

(max_part[u]

, all - max_part[u]);

if(max_part[u]

< max_part[root]

) root = u;

}void

dfs2

(int u,

int fa)

}int

calc

(int u,

int now)

void

solve

(int u)

}int

main()

all = n, max_part[0]

= n, root =0;

ans =0;

dfs1(1

,0);

solve

(root)

;printf

("%d\n"

, ans);}

return0;

}

詳解點分治

本篇隨筆講解演算法競賽中的點分治澱粉質演算法。點分治是一種在樹上進行路徑靜態統計的演算法。所謂樹上的靜態統計,並不是像樹剖一樣維護路徑最值 路徑和之類的統計。那樣的話,這個演算法的存在就沒什麼意義了。來上道小題體會一下點分治的解決問題。給定一棵有n個節點的帶邊權無根樹。求長度不超過k的路徑有多少條。...

點分治 模板 詳解

動態點分治學了以後會在後面 update 的啦 好久沒頹 blog 了 今天來寫一發 最近幾個月就學了這乙個東西啊 好了 進入正題 舌尖上的澱粉質 q1 點分治是什麼?a1 就是像分治一樣把樹上的點咔擦成幾個小樹,然後繼續咔擦下去處理問題啦 像你把西蘭花掰開一樣 q2 點分治能用來幹什麼?a2 據我...

點分治 動態點分治

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