學習筆記 Kruscal 重構樹

2022-04-29 05:48:07 字數 2023 閱讀 5495

網上感覺沒有什麼很詳細 + 證明的講解啊)

前置:kruskal 求最小生成樹。

這個演算法可以將一棵樹 / 無向連通圖重構成一顆有性質的新樹。

演算法可以解決一些樹上瓶頸邊權之類的問題,可以把需要持久化的並查集給代替掉。

設 \(f_i\) 為 \(i\) 所在聯通塊的根。

演算法流程和 kruskal 最小生成樹的過程非常類似:

將所有邊按邊權從小到大排序

順序遍歷每條邊 \((u, v, w)\),若 \(u, v\) 已經聯通跳過,否則建立乙個新點 \(x\),讓 \(x\) 作為 \(f_u\) 與 \(f_v\) 的父親(即連 \(x \rightarrow f_u\) 和 \(x \rightarrow f_v\) 的有向邊),然後讓 \(f_u = f_v = x\)。這個新點的點權是 \(w\)。

時間複雜度 \(o(m \log m + n \log n)\)。

最後,以最後乙個建立的新點作為 \(rt\) ,就是一顆重構樹了(下面是乙個無向圖聯通變成重構樹的例子,排序後第 \(i\) 條邊的編號是 \(n + i\),點權是紅色,藍色是新點,黑色是原來的點)。

這棵樹有如下性質:

如果求最大生成樹,反著排序,那麼偏序關係都反轉,就不贅述了。

為了方便我自己創了乙個名詞,如果從小到大排序形成的大根堆叫 kruscal 最小重構樹,反之叫 kruscal 最大重構樹。

[noi2018]歸程

預處理 \(d_i\) 表示從 \(i\) 到 \(1\) 的最短路徑,這個反著建邊跑最短路就行了。

如果可以離線,那麼從大到小排序邊權,然後執行 kruscal,維護一下每個聯通塊的最小值,每次在嘗試完 merge \(>p\) 的所有邊後,對應 \(o(1)\) 查詢就可以了。

用 kruscal 重構樹的話,從大到小排序邊權建 kruscal 最大重構樹,那麼從 \(v\) 出發經過 \(> p\) 的邊能到的點 \(=\)

\(v\) 的祖先中深度最小的滿足點權 \(> p\) 的點 \(x\) 的子樹中所有原來的點。

由於有單調性,倍增跳就好了,子樹點權最小,預處理一下就好了。

複雜度 \(o(m \log m +(n + q) \log n)\)

鏈結

#include #include #include #include #include #include using namespace std;

typedef pairpii;

const int n = 200005, m = 400005, inf = 2e9, l = 19;

int n, m, q, k, s, lastans, d[n], f[n << 1], w[n << 1], val[n << 1], cnt, fa[n << 1][l];

int head[n], nume = 0;

bool vis[n];

priority_queue, greater> q;

struct e e[m << 1];

vectorg[n << 1];

struct edge

} b[m];

void inline add(int u, int v, int w) ;

head[u] = nume;

}void inline clear()

void inline dijkstra() }}

}int find(int x)

void inline kruscal()

}void dfs(int u)

}int main() ;

}dijkstra();

kruscal();

dfs(2 * n - 1);

scanf("%d%d%d", &q, &k, &s);

while (q--)

if (t)

clear();

}return 0;

}

kruscal重構樹略解

這道題珂以用啟發式合併 主席樹來做 離線做法就不行了 我們就要用乙個叫做kruscal重構樹的東西來解決這個問題 克魯斯卡爾重構樹可以用來解決一類諸如 查詢從某個點出發經過邊權不超過val的邊所能到達的節點 的問題 首先不難發現,上面這個問題肯定是在最小生成樹上走最優,其他邊都可以不用去管 krus...

Kruskal重構樹 學習筆記

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

學習筆記 Kruskal重構樹

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