次小生成樹

2022-05-01 19:03:09 字數 1785 閱讀 4352

我們已經熟知了求最小生成樹的方法,用kruskal,prim演算法都可以搞

那麼我們如何求次小生成樹呢?

這裡次小生成樹的定義是

邊權和嚴格大於最小生成樹的邊權和最小的生成樹

次小生成樹嘛,肯定和最小生成樹脫不了關係

那麼我們首先求出最小生成樹

接下來,乙個比較顯然的思路是

列舉每一條未加入最小生成樹的邊,加入最小生成樹,同時在最小生成樹中刪除邊權最大的邊

如果你想到了這裡並寫出了**,那麼恭喜你

你在裡成功還有一步之遙成功掉進坑里了

比如下面的例子

藍邊表示最小生成樹中的邊,黃邊表示新加入的邊

在這種情況下,如果僅僅記錄最大值的話,得到的答案一定是錯的

所以我們還要記錄嚴格小於最大值的最大值

當產生衝突的時候我們需要刪除嚴格小於最大值的最大值

但是這樣效率太低了,每一次查詢都是\(o(n)\)的

有沒有更好的方法呢?

不要忘了,最小生成樹它是一棵樹呀

樹的鏈上最大最小值操作,你想到了什麼?

沒錯!樹上倍增

我們在倍增的過程中記錄下最大值和嚴格小於最大值的最大值

這樣每次查詢的複雜度就變成\(log(n)\)啦

整個演算法的流程大概是

求出最小生成樹

構造出倍增陣列

每次樹上倍增查詢

用kruskal是\(o(m\log m+q\log (n))\)

用prim是\(o(n\log n+q\log (n))\)

q為詢問次數

放一道裸題

// luogu-judger-enable-o2

#include#include#include#include#include#define int long long

using namespace std;

const int maxn=400001;

const int inf=1e15+10;

inline int read()

while(c>='0'&&c<='9')

return x*f;

}struct edge

e[maxn];

int enum=1;

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

struct node

edge[maxn];

int head[maxn];

int num=1;

int n,m;

int fa[maxn],vis[maxn],sum;

int deep[maxn],f[maxn][21],maxx[maxn][21],minx[maxn][21];

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

int find(int x)

int unionn(int x,int y)

int comp(const edge &a,const edge &b)

}}int lca(int x,int y)

int findmax(int x,int lca,int val)

}return ans;

}void work()

printf("%lld",ans);

}main()

kruskal();

deep[1]=1;

dfs(1,0);

pre();

work();

return 0;

}

最小生成樹 次小生成樹

一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...

次小生成樹

演算法引入 設g v,e,w 是連通的無向圖,t是圖g的一棵最小生成樹 如果有另一棵樹t1,滿足不存在樹t t t1 則稱t1是圖g的次小生成樹 演算法思想 鄰集的概念 由t進行一次可行交換得到的新的生成樹所組成的集合,稱為樹t的鄰集,記為n t 設t是圖g的最小生成樹,如果t1滿足 t1 min,...

次小生成樹

分類 圖論 2013 02 12 15 03 32人閱讀收藏 舉報次小生成樹 在求最小生成樹時,用陣列path i j 來表示mst中i到j最大邊權。求完後,直接列舉所有不在mst中的邊,把它加入到mst中構成一棵新的樹,且該樹有環,此環是由剛加入的邊 i,j 造成的,所以可以通過刪除path i ...