樹的直徑 樹的重心與樹的點分治學習筆記

2021-08-13 04:27:35 字數 3657 閱讀 5021

樹的直徑是指樹上的最長簡單路

任選一點w為起點,對樹進行搜尋,找出離w最遠的點u

u為起點,再進行搜尋,找出離u最遠的點v。則uv的路徑長度即為樹的直徑。

簡單證明:

如果w在直徑上,那麼u一定是直徑的乙個端點。反證:若u不是端點,設直徑的兩端為st,則dist(w, u) > dist(u, t)dist(w, u) > dist(u, s),則最長路不是s - t了,與假設矛盾。

如果w不在直徑上,且w到其距最遠點u的路徑與直徑一定有一交點c,那麼由上乙個證明可知,u是直徑的乙個端點。

如果w到最遠點u的路徑與直徑沒有交點,設直徑的兩端為st,那麼dist(w, u) > dist(w, c) + dist(c, t),推出dist(s, c) + dist(w, u) + dist(w, c) > dist(s, c) + dist(c, t) = dist(s, t),最長路不是s - t與假設矛盾。

因此w到最遠點u的路徑與直徑必有交點。

s-----------c-----------t

|w------u

樹的重心 —— by patrickzhou

何謂重心

樹的重心:找到乙個點,以它為整棵樹的根,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹盡可能平衡。

樹的重心有下面幾條常見性質:

定義1:找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心。

定義2:以這個點為根,那麼所有的子樹(不算整個樹自身)的大小都不超過整個樹大小的一半。

性質1:樹中所有點到某個點的距離和中,到重心的距離和是最小的;如果有兩個重心,那麼他們的距離和一樣。

性質2:把兩個樹通過一條邊相連得到乙個新的樹,那麼新的樹的重心在連線原來兩個樹的重心的路徑上。

性質3:把乙個樹新增或刪除乙個葉子,那麼它的重心最多隻移動一條邊的距離。

樹的重心可以通過簡單的兩次搜尋求出,第一遍搜尋求出以i為根的每個結點的子結點數量son[i],第二遍搜尋找出以 u 為整棵樹的根使max(son[u], n - son[u])最小的結點u

實際上這兩步操作可以在一次遍歷中解決。對結點u的每乙個兒子v,遞迴的處理v,求出son[v],然後判斷是否是結點數最多的子樹,處理完所有子結點後,判斷u是否為重心。

void dfs(int u, int fa) 

res = max(res, n - son[u]);

if(res < size)

}

我們可以發現:

對於乙個點,顯然只有經過它的路徑和不經過它的路徑。

我們不考慮不經過它的路徑。

經過它的路徑的兩個端點一定它在的兩個子樹裡。

以它為根統計到它子樹節點的距離。這樣的單獨的距離或兩段距離之和一定經過這個根節點。

對於每個點我們都可以這樣計算。

可是當樹退化成一條鏈的時候。複雜度就會很高,不斷的遞迴找子樹。

所以我們需要按樹的重心(因為重心刪掉後最大子樹節點數最小)來找這些點,這樣可以把複雜度控制在 o(

nlog

n)。

所以點分治的思想就是:

找重心把它作為根

解決根的路徑問題

遞迴子樹解決子問題(重複一二步驟)

針對每題不同的只有cal()

luogu p3806 【模板】點分治1

size是以刪掉u後,最大連通塊的大小。

size[0]是整棵子樹大小,一開始rt = 0,用之後更小size值更新rt

sum是當前子樹內的總點數。

temnum是子樹編號。

cnt2temnumcal()裡要記得每次都要清一次空。因為cnt2每次是針對不同的重心的,而temnum每次針對是不同重心的子樹的。

#include 

using

namespace

std;

const

int n = 1e5 + 5;

struct edge e[n << 1];

struct seg seg1[n << 1];

int n, q, sum;

bool ok[10000005];

int head[n], cnt = 0;

void add(int x, int y, int z)

int cnt2 = 0;

void add2(int dis, int pos)

int rt;

int son[n], size[n], vis[n];

void dfs1(int u, int fa)

size[u] = max(size[u], sum - son[u]);

if (size[u] < size[rt]) rt = u;

}int dis[n];

void dfs2(int u, int fa, int num)

}void cal(int u)

for (int i = 1; i < cnt2; i ++)

for (int j = i + 1; j <= cnt2; j ++)

if (seg1[i].pos != seg1[j].pos)

ok[seg1[i].dis + seg1[j].dis] = 1;

}void solve(int u)

}int main()

size[0] = sum = n;

dfs1(1, 0);

solve(rt);

for (int i = 1; i <= q; i ++)

return

0;}

樹的重心 樹的直徑

樹的重心 樹的重心定義為 找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹盡可能平衡.實際上樹的重心在樹的點分治中有重要的作用,可以避免n 2的極端複雜度 從退化鏈的一端出發 保證nlogn的複雜度,利用樹型dp可以很好地求樹的重心.求樹的重心 模...

樹的直徑 樹的重心

樹的直徑 定義 那麼樹上最遠的兩個點,他們之間的距離,就被稱之為樹的直徑。樹的直徑的性質 1.直徑兩端點一定是兩個葉子節點。2.距離任意點最遠的點一定是直徑的乙個端點,這個基於貪心求直徑方法的正確性 可以得出。3.對於兩棵樹,如果第一棵樹直徑兩端點為 u,v 第二棵樹直徑兩端點為 x,y 用條邊將兩...

樹的直徑與重心

樹的直徑,指樹上最長的不重複經過同乙個點的路徑。方法 先從任意一點p pp出發,找離它最遠的點q qq,再從點q qq出發,找離它最遠的點w ww,w ww到q qq的距離就是的直徑 具體實現可以使用兩次dfs dfsdf s。演算法證明 反證法 include using namespace st...