在一張無向圖中,詢問乙個點對(u,v),找出從u到v的一條簡單路徑,使路徑上所有邊中最大值最小。
應用:次小生成樹
給定一張無向圖,求出一棵生成樹,其所有邊的權值之和僅次於最小生成樹的權值之和(如果有多個最小生成樹的話次小生成樹就是最小生成樹)。
思路:先求出最小生成樹。列舉所有樹外的邊加入最小生成樹,則一定會構成乙個環,此時需要在這個環中任意斷開一條邊,使其依然成為一棵樹。為了盡量使權值之和最小,我們需要斷開樹上加入的邊的兩端點之間權值最大的邊,則問題變為最小瓶頸路問題,可以用lca解決
即題目只需要查詢一對st到ed
例題:p1396 營救
題意:給n個點m條邊的無向圖
給st和ed,找一條從st至ed的路徑,使得經過的邊權最大值最小。
輸出路徑的最大邊權
思路:1.二分最大值,check為判斷只走小於等於mid的邊能否從st到達ed
2.kruksal,從小到大合併邊,當st和ed在同一連通塊的時候答案為當前合併的邊的邊權
code:
**在這
即題目多次給出st和ed,需要查詢多次。
例題:p2245 星際導航
題意:給n個點m條邊的無向圖,
q組詢問,給st和ed,找一條從st至ed的路徑,使得經過的邊權最大值最小。
輸出路徑的最大邊權
如果st無法到達ed輸出impossible
思路:1.最小生成樹+lca
求出最小生成樹之後求st到ed之間的最大值,用lca來求最值
結論很顯然就不證明了
2.kruskal重構樹
kruskla重構樹的基礎應用
ps:題目可能有多個連通塊
code1:
最小生成樹+lca
**裡面lca用邊權樹剖實現的
#include
using
namespace std;
//#define int long long
const
int maxm=
4e5+5;
struct nodee[maxm]
;struct edgeee[maxm]
;int num;
int head[maxm]
,nt[maxm]
,to[maxm]
,w[maxm]
,cnt;
int sz[maxm]
,son[maxm]
,top[maxm]
,d[maxm]
,id[maxm]
,fa[maxm]
,rk[maxm]
,idx;
int a[maxm<<2]
;int pre[maxm]
;int mark[maxm]
;int v[maxm]
;int n,m;
void
init()
cnt=1;
num=0;
}bool
cmp(node a,node b)
void
add(
int x,
int y)
intffind
(int x)
void
dfs1
(int x)}}
void
dfs2
(int x,
int tp)
for(
int i=head[x]
;i;i=nt[i])}
void
pushup
(int node)
void
build
(int l,
int r,
int node)
int mid=
(l+r)/2
;build
(l,mid,node*2)
;build
(mid+
1,r,node*2+
1);pushup
(node);}
intask
(int st,
int ed,
int l,
int r,
int node)
int mid=
(l+r)/2
;int ans=0;
if(st<=mid)
if(ed>=mid+1)
return ans;
}void
kruskal()
;add
(e[i]
.a,e[i]
.b);
add(e[i]
.b,e[i]
.a);}}
for(
int i=
1;i<=n;i++)}
for(
int i=
1;i<=num;i++
)build(1
,n,1);
//建樹
}int
lca(
int x,
int y)
if(d[x]
>d[y]
)swap
(x,y)
; ans=
max(ans,
ask(id[son[x]
],id[y],1
,n,1))
;return ans;
}signed
main()
kruskal()
;int q;
cin>>q;
while
(q--
)else
}return0;
}
code2:
kruskal重構樹
注意陣列別開小了
#include
using
namespace std;
//#define int long long
const
int maxm=
4e5+5;
struct nodee[maxm]
;int head[maxm]
,nt[maxm]
,to[maxm]
,cnt;
int sz[maxm]
,son[maxm]
,fa[maxm]
,top[maxm]
,d[maxm]
;int pre[maxm]
;int mark[maxm]
;int val[maxm]
;int n,m;
bool
cmp(node a,node b)
void
init()
cnt=1;
}void
add(
int x,
int y)
void
dfs1
(int x)}}
void
dfs2
(int x,
int tp)
for(
int i=head[x]
;i;i=nt[i])}
intffind
(int x)
void
kruskal()
}for
(int i=
1;i<=n;i++)}
}int
lca(
int x,
int y)
if(d[x]
>d[y]
)swap
(x,y)
;return x;
}signed
main()
kruskal()
;int q;
cin>>q;
while
(q--
)else
}return0;
}
最小瓶頸路
題目 uva 534 題目大意 有兩隻青蛙,在兩塊不同的石頭上,有乙隻想要去拜訪另乙隻,要求通過它石頭進行跳躍然後在一起呀在一起,可想而知,由於石頭有很多,他們中間的路徑也有很多,現在要求求乙個長度 從每條路徑裡面挑出那步跨越最大的,然後從這些跨越最大的裡面挑出最小的。分析 flody 的改版 in...
P1396 營救 最小瓶頸路
這個題貌似時最小瓶頸路的前身,單次離線查詢。思路 1.最小生成樹kru skal kruskal kruska l,當s,t s,ts,t連通時的對應邊權值為答案。include using namespace std typedef long long ll const int n 1e4 5,m...
UVa 11354 邦德(最小瓶頸路 LCA)
題意 有n個城市m條道路,每條道路有乙個危險係數。先在有若干個詢問,要求找到一條從s到t的路,使得途徑所有邊的最大危險係數最小。思路 最小瓶頸路肯定是在最小生成樹上的。所有先求最小生成樹。然後將它轉化成有根樹,讓fa i 和cost i 分別表示結點i的父親編號和它與父親之間的邊權l i 表示結點i...