洛谷p4180嚴格次小生成樹

2022-08-15 05:00:13 字數 3945 閱讀 7745

題意:求嚴格的次小生成樹

嚴格次小生成樹:(value(e)表示邊e的權值) ∑e∈e

m​​ value(e)

s​​ value(e)(em為最小生成樹邊集,es為次小生成樹邊集)

就是次小生成樹邊權和一定要小於最小生成樹,   而非嚴格的就不一定,也可能等於。

非嚴格次小生成樹求法:是在最小生成樹邊集外   找到一條邊(假設兩點為u,v)(一定大於等於最小生成樹里的邊),替換掉

最小生成樹中u,v之間最大邊,使得兩者差值最小。  主要是要儲存最小生成樹兩點之間最大邊。

嚴格次小生成樹與非嚴格相似,但是要儲存兩點之間  最大邊和次大邊, 因為最小生成樹邊集外 的邊等於最大邊時,代替次大邊

否則就是代替最大邊。  而這裡用到了lca最近公共祖先,為了保證聯通

如圖:假設除去紫色的邊是  最小生成樹,  我們的目標是用紫色的邊代替   環中的小於紫邊最大的邊。

所以這裡用到了lca,假設紫邊兩點為u,v,  先找到u,v的最近公共祖先點 fa,就分兩邊 找u,fa之間的最大小於紫邊的邊  和v,fa之間最大小於紫邊的邊

這樣遍歷每條不在最小生成樹中的邊,找到最小的   紫邊與代替邊的差值,加上最小生成樹邊權和就是答案。

最後我們來總結下步驟:

第一步:用kruskal 找到最小生成樹,記算邊權和,和 標記最小生成樹中的邊。

第二步:dfs搜尋 記錄最小生成樹中兩點的最近公共祖先, 並用同樣的方式記錄 兩點之間最大邊和最次邊。

第三步:列舉不在最小生成樹中的邊,lca找到邊兩點的最近公共祖先,分兩邊查詢最大小於這條邊的邊權值。

最後:找到最小的差值加上最小生成樹邊權和即可。

**中一直貫徹著倍增的思想。詳細可以看**:

#include#include

#include

#include

#define inf 0x3f3f3f3f

using

namespace

std;

typedef

long

long

ll;

const

int maxn=1e5+100

;const

int maxm=3e5+100

; struct

nodee[

2*maxm];

struct

edgeee[maxm];

int head[maxn],bz[maxn][22];//

bz[i][j]記錄i的2^j祖先

int maxi[maxn][22],mini[maxn][22

],lg[maxn];

//maxi[i][j],記錄i到2^j祖先之間的最大邊權值,mini是記錄次邊值

//lg[i]表示log_2(i)+1,用來優化lca的,可以不用

intdepth[maxn],fa[maxn],n,m,cnt;

bool

cmp(edge a,edge b)

void add(int u,int v,int

w)void dfs(int f,int fath)//

記錄最小生成樹中兩點之間的最近公共祖先和最大邊,次大邊

for(int i=head[f];i!=-1;i=e[i].nxt)

}

}int lca(int x,int y)//

lca求最近公共祖先

int find(int

x)int qmax(int u,int v,int w)//

找到u,v之間小於 w大最大邊

}return

ans;

}int

main()

}dfs(

1,0);

int ans=inf;

for(int i=1;i<=m;i++)//

列舉不在最小生成樹的邊

}printf(

"%lld\n

",sum+ans);//

答案就是最小生成樹邊權和加最小差值

如圖:假設除去紫色的邊是  最小生成樹,  我們的目標是用紫色的邊代替   環中的小於紫邊最大的邊。

所以這裡用到了lca,假設紫邊兩點為u,v,  先找到u,v的最近公共祖先點 fa,就分兩邊 找u,fa之間的最大小於紫邊的邊  和v,fa之間最大小於紫邊的邊

這樣遍歷每條不在最小生成樹中的邊,找到最小的   紫邊與代替邊的差值,加上最小生成樹邊權和就是答案。

最後我們來總結下步驟:

第一步:用kruskal 找到最小生成樹,記算邊權和,和 標記最小生成樹中的邊。

第二步:dfs搜尋 記錄最小生成樹中兩點的最近公共祖先, 並用同樣的方式記錄 兩點之間最大邊和最次邊。

第三步:列舉不在最小生成樹中的邊,lca找到邊兩點的最近公共祖先,分兩邊查詢最大小於這條邊的邊權值。

最後:找到最小的差值加上最小生成樹邊權和即可。

**中一直貫徹著倍增的思想。詳細可以看**:

#include#include

#include

#include

#define inf 0x3f3f3f3f

using

namespace

std;

typedef

long

long

ll;

const

int maxn=1e5+100

;const

int maxm=3e5+100

; struct

nodee[

2*maxm];

struct

edgeee[maxm];

int head[maxn],bz[maxn][22];//

bz[i][j]記錄i的2^j祖先

int maxi[maxn][22],mini[maxn][22

],lg[maxn];

//maxi[i][j],記錄i到2^j祖先之間的最大邊權值,mini是記錄次邊值

//lg[i]表示log_2(i)+1,用來優化lca的,可以不用

intdepth[maxn],fa[maxn],n,m,cnt;

bool

cmp(edge a,edge b)

void add(int u,int v,int

w)void dfs(int f,int fath)//

記錄最小生成樹中兩點之間的最近公共祖先和最大邊,次大邊

for(int i=head[f];i!=-1;i=e[i].nxt)

}

}int lca(int x,int y)//

lca求最近公共祖先

int find(int

x)int qmax(int u,int v,int w)//

找到u,v之間小於 w大最大邊

}return

ans;

}int

main()

}dfs(

1,0);

int ans=inf;

for(int i=1;i<=m;i++)//

列舉不在最小生成樹的邊

}printf(

"%lld\n

",sum+ans);//

答案就是最小生成樹邊權和加最小差值

return0;

}

P4180 嚴格次小生成樹 BJWC2010

題目鏈結 當時在暑假早就講了這道題了,只不過我現在才做了這道題。題解 我們要求次小生成樹的話,考慮先把最小生成樹求出來,因為如果我們用求最小生成樹的話,邊早已經從大到小排序好了,所以次小生成樹的就是替換最小生成樹上的一條邊所得。那麼考慮如何來替換那一條邊,要保證嚴格次小,那麼我們需要替換掉最小生成樹...

P4180 BJWC2010 嚴格次小生成樹

題目 最小生成樹都會吧?不會的戳這裡 接下來我們用lca求每一條非樹邊在樹上環的最大邊權和次大邊權,然後求乙個min s mx v,s mx2 v,mn 就可以了,注意如果mx v,第一項不比較.code include include include include include include...

嚴格次小生成樹

顧名思義。生成樹,邊權和嚴格小於最小生成樹 一定和最小生成樹有關係。實際上,有 結論1 嚴格次小生成樹只在最小生成樹上改動一條邊 證明 改動一條邊有意義的話,必然改完這條邊,總和變大。那麼這至少是嚴格次小生成樹的最大值。再改一條也沒有意義。結論2 改動的那條邊w,一定是新加入的那條邊覆蓋的樹鏈的最大...