kruskal重構樹學習筆記

2022-05-07 01:03:11 字數 2813 閱讀 9392

\(8102ioncc\) 中考到了,本蒟蒻不會,所以學一下。

\(kruskal​\) 求最小(大)生成樹,樹上求 \(lca​\)。

\(kruskal\) 重構樹可以解決瓶頸路問題(如:\(noip2013\)

\(d1t3\) 貨車運輸,可以當做模板題來做,本文中也將此題作為例題);

我們來思考一下 \(kruskal\) 求最小(大)生成樹的過程(後文中以最大生成樹為例),大致過程可以概述為:將圖中所有邊從大到小排序,列舉,如果該邊左右兩端的點不在同乙個聯通塊裡就連起來,即:該邊在最大生成樹上。(其中聯通塊用 \(dsu\) 維護)

\(kruskal\) 重構樹就是把最大生成樹上的邊建成樹,實現過程:在 \(kruskal\) 演算法進行過程中,對於每次要連線的兩個聯通塊 \(a\) 和 \(b\),用乙個新的節點當做 \(a\)

\(b\) 在重構樹中的父親節點,並把新節點的點權設為連線聯通塊的邊的邊權,以此操作來代替連邊操作,聯通塊同樣用 \(dsu\) ,只不過是把 \(a\)

\(b\) 併入新節點。

有乙個比較明顯的性質:最後建成的樹一定是乙個堆(大根堆小根堆視情況而定),因為邊是按大小順序列舉的,如果我表達不太清楚 \((qaq)\) ,可以配合**來學習。

具體來說,如果 \(kruskal\) 求最大生成樹的過程是這樣的:

那麼建樹過程大概就是這樣的(藍色是新建節點):

可以很直觀地看到這真的是個堆,上文已經提到,不再贅述。

\(u,v\) 之間的瓶頸路,即:\(u,v\) 在重構樹中的 \(lca\) 的點權。因為建樹過程和 \(kruskal\) 同步進行,所以每個新建節點的點權是可以連線兩棵子樹所在聯通塊的最大邊權,同時因為堆的性質 \(lca\) 是整顆以 \(lca\) 為根的子樹中的最小值。(本人語文水平不及格,可以結合和 \(kruskal\) 的過程來理解)

\(p.s.\) 同樣可以利用該性質證明瓶頸路一定在最大生成樹上。

這是一道模板題。

**如下:

#include #include #include inline int in() 

const int n = 1e5+5, m = 5e5+5;

struct info

}a[m+n];

int n, m, tot, fa[n<<1];

namespace kruskal_tree e[n];

int head[n<<1], val[n<<1], cnt=1, size[n<<1], hson[n<<1], fro[n<<1], dep[n<<1];

inline void jb(int u, int v) ;

head[u]=cnt;

}void dfs_h(int u)

}void dfs_f(int u, int father)

inline int lca(int u, int v)

return dep[u]一句話題解: \(dijsktra\) 預處理 \(1\) 為起點的最短路(權值為長度);建好 \(kruskal\) 重構樹(海拔為權值),每次查詢 \(v\) 時樹上倍增一直跳就好了 \(qwq\)。

時間複雜度:\(\theta \big(t \times \big (mlogm+(q+n)logn \big) \big)\)

**如下:

#include #include #include #include typedef long long ll;

inline int in()

const int n = 2e5+5, m = 4e5+5;

struct info

}a[m];

struct edge e[m<<1];

int head[n], cnt, n, m, tot, fa[m], d[n];

bool vis[n];

templateinline void chk_min(t &_, t __)

namespace kt e[n<<1];

int cnt=1, head[n<<1], min[n<<1], dep[n<<1], fa[19][n<<1], a[n<<1], l[19];

inline void jb(int u, int v) ;

head[u]=cnt;

}void dfs(int u)

}inline int query(int u, int s)

}inline void add_edge(int u, int v, int w) , head[u]=cnt;

e[++cnt]=(edge), head[v]=cnt;

}typedef std::pair pii;

inline void dijkstra()

}}int get_fa(int u)

inline void kruskal(info *e)

}inline void init()

int main() ;

add_edge(u, v, l);

}dijkstra();

kruskal(a);

kt::dep[tot]=1;

kt::dfs(tot);

int q=in(), k=in(), s=in(), ans=0, v, a;

while(q--)

}return 0;

}

Kruskal重構樹 學習筆記

kruskal重構樹 性質 1.是乙個小 大根堆 由建樹時邊權的排序方式決定 2.lca u,v 的權值是原圖u到v路徑上最大 小邊權的最小 大值 由建樹時邊權的排序方式決定 kruskal重構樹 建樹 模仿kruskal的過程,先將邊權排序 排序方式決定何種性質接下來說明 依次遍歷每條邊 若該邊連...

學習筆記 Kruskal重構樹

kruskal 求最值生成樹時需要通過邊合併兩個之前不相連的連通塊 這時候通過建立虛點表示兩點之間有連邊,同時將邊的資訊記錄到虛點上 所以如果查詢原圖上的兩點間路徑上的極值,可以考慮維護重構樹路徑上點權的資訊 大概長成這樣子,變數名還是比較大眾化的 nodes n for int i 1 i m i...

Kruskal重構樹學習筆記

這裡是kruskal重構樹學習筆記。kruskal重構樹,是用於求出有關一張圖中,某點僅經過邊權 leq 某個值 v 的邊所得到的子圖的有關資訊的工具。但事實上,其應用還有更多。我們先講述其構造方法 將所有邊按照邊權遞增排序。依次列舉每一條邊。假如此時邊的兩個端點處於兩個不同集合中,按照常規krus...