【题目】
Description
给你 n n n 个点的无向图( 1 1 1 ≤ n n n ≤ 15 , 000 15,000 15,000),记为: 1 … n 1…n 1…n。
图中有 m m m 条边( 1 1 1 ≤ m m m ≤ 30 , 000 30,000 30,000),第 j j j 条边的长度为: d j d_j dj( 1 1 1 ≤ d j d_j dj ≤ 1 , 000 , 000 , 000 1,000,000,000 1,000,000,000)。
现在有 k k k 个询问( 1 1 1 ≤ k k k ≤ 20 , 000 20,000 20,000)。
每个询问的格式是: a a a b b b,表示询问从 a a a 点走到 b b b 点的所有路径中,最长的边最小值是多少?
Input
第一行: n , m , k n, m, k n,m,k。
第 2.. m + 1 2..m+1 2..m+1 行:三个正整数: x , y x, y x,y 和 d d d( 1 1 1 ≤ x x x ≤ n n n; 1 1 1 ≤ y y y ≤ n n n)。表示 x x x 与 y y y 之间有一条长度为 d d d 的边。
第 m + 2.. m + k + 1 m+2..m+k+1 m+2..m+k+1 行:每行两个整数 a a a b b b,表示询问从 A A A 点走到 B B B 点的所有路径中,最长的边最小值是多少?
Output
对每个询问,输出最长的边最小值是多少。
Sample Input
6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
Sample Output
5
5
5
4
4
7
4
5
HINT
1
1
1 ≤
n
n
n ≤
15
,
000
15,000
15,000
1
1
1 ≤
m
m
m ≤
30
,
000
30,000
30,000
1
1
1 ≤
d
j
d_j
dj ≤
1
,
000
,
000
,
000
1,000,000,000
1,000,000,000
1
1
1 ≤
k
k
k ≤
15
,
000
15,000
15,000
【分析】
这道题有两种解法,个人觉得这两种都不错哦
题解 1 1 1:Kruskal+倍增
很容易可以看出来,题目中要求的东西(实际上叫做最小瓶颈路)一定在最小生成树上
因为如果要使最大的边最小,我们肯定就用最小的边将图连通,那就是最小生成树
那么就先用做一遍最小生成树,然后把在最小生成树上的边留下来,其它的就可以不要了
怎么求这个最长的边最小值是多少呢?考虑倍增,我们记录 M a x i , j Max_{i,j} Maxi,j 表示从 i i i 跳 2 j 2^j 2j 步内的最大值
然后剩下的就和倍增求 l c a lca lca 差不多了,可以直接套模板(只用改一点东西)
题解 2 2 2:Kruskal重构树
今天又学了个神奇东西
K r u s k a l Kruskal Kruskal 重构树具体是什么东西我也就不细说了(推荐一下这篇博客)
对于这道题, K r u s k a l Kruskal Kruskal 重构树有一个很好的性质,即原树中两点之间的最小瓶颈路等于新树上两点的 l c a lca lca 的点权
根据这个性质,我们把 K r u s k a l Kruskal Kruskal 重构树建造出来,每次找个 l c a lca lca 就行了
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 15005
#define M 30005
#define inf (1ll<<31ll)-1
using namespace std;
int n,m,k,t;
struct edge{int u,v,w;}a[M];
int first[N],v[M],w[M],nxt[M];
int dep[N],father[N],fa[N][20],Max[N][20];
bool comp(const edge &p,const edge &q) {return p.w<q.w;}
void add(int x,int y,int z) {nxt[++t]=first[x];first[x]=t;v[t]=y;w[t]=z;}
int find(int x)
{
if(father[x]!=x)
father[x]=find(father[x]);
return father[x];
}
void Kruskal()
{
int x,y,i;
sort(a+1,a+m+1,comp);
for(i=1;i<=m;++i)
{
x=find(a[i].u);
y=find(a[i].v);
if(x!=y)
{
father[x]=y;
add(a[i].u,a[i].v,a[i].w);
add(a[i].v,a[i].u,a[i].w);
}
}
}
void dfs(int x)
{
int i,j;
for(i=1;i<=17;++i)
{
fa[x][i]=fa[fa[x][i-1]][i-1];
Max[x][i]=max(Max[x][i-1],Max[fa[x][i-1]][i-1]);
}
for(i=first[x];i;i=nxt[i])
{
j=v[i];
if(j!=fa[x][0])
{
fa[j][0]=x;
Max[j][0]=w[i];
dep[j]=dep[x]+1;
dfs(j);
}
}
}
int get(int x,int y)
{
int i,j,maxn=0;
if(dep[x]<dep[y]) swap(x,y);
for(i=17;~i;--i)
if(dep[fa[x][i]]>=dep[y])
maxn=max(maxn,Max[x][i]),x=fa[x][i];
if(x==y) return maxn;
for(i=17;~i;--i)
{
if(fa[x][i]!=fa[y][i])
{
maxn=max(maxn,Max[x][i]),x=fa[x][i];
maxn=max(maxn,Max[y][i]),y=fa[y][i];
}
}
maxn=max(maxn,Max[x][0]);
maxn=max(maxn,Max[y][0]);
return maxn;
}
int main()
{
int x,y,i,j;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;++i) father[i]=i;
for(i=1;i<=m;++i) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
Kruskal();
dep[1]=1,dfs(1);
for(i=1;i<=k;++i)
{
scanf("%d%d",&x,&y);
printf("%d\n",get(x,y));
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,k,tot;
struct edge{int u,v,w;}a[N];
int dep[N],val[N],father[N],son[N][2],fa[N][20];
bool comp(const edge &p,const edge &q) {return p.w<q.w;}
int find(int x)
{
if(father[x]!=x)
father[x]=find(father[x]);
return father[x];
}
void Kruskal()
{
int x,y,i;
sort(a+1,a+m+1,comp);
for(i=1;i<=m;++i)
{
x=find(a[i].u);
y=find(a[i].v);
if(x!=y)
{
tot++,son[tot][0]=x,son[tot][1]=y;
father[x]=father[y]=fa[x][0]=fa[y][0]=tot;
val[tot]=a[i].w;
}
}
}
void dfs(int x)
{
if(son[x][0]) dep[son[x][0]]=dep[x]+1,dfs(son[x][0]);
if(son[x][1]) dep[son[x][1]]=dep[x]+1,dfs(son[x][1]);
}
int lca(int x,int y)
{
int i,j;
if(dep[x]<dep[y]) swap(x,y);
for(i=17;~i;--i)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(i=17;~i;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main()
{
freopen("1.in","r",stdin);
int x,y,i,j;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=(n<<1);++i) father[i]=i;
for(i=1;i<=m;++i) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
tot=n,Kruskal();
dep[tot]=1,dfs(tot);
for(j=1;j<=17;++j)
for(i=1;i<=tot;++i)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(i=1;i<=k;++i)
{
scanf("%d%d",&x,&y);
printf("%d\n",val[lca(x,y)]);
}
return 0;
}