题意:
n个点,m个边,生成一个最小生成树,问对于不在最小生成树的边将其边权最大改为多少后,最小生成树可以包含该边
输出m-(n-1)个答案
如果n==m-1的话,不需要输出任何东西
题解:
这个题和CodeForces - 609E 是完全一样的,就是输出不一样,换了问法,代码改改就能过
题解链接
对于不在最下生成树的边(u,v)边权为w,答案是u和v之间的路径上的最大边权值
为什么呢?因为如果存在u到v路径上的一个边权值大于边(u,v),那就可以用(u,v)这个边来代替它,这样不满足题意
所以要让(u,v)加入到最小生成树里面,就要让边权w=最大边权值
那这个u和v之间的路径上的最大边权值怎么求?
u和v是在树上,路径也是树上的路径,所以我们可以求出u和v的最近公共祖先x,然后利用倍增来求u到x,v到x,在这个过程中记录最大路径
mx=max(mx(u->x) , mx(v->x))
代码:
其中代码注释了一部分,也是求u到v之间的路径上的最大边权值,只是写法不同
#include<bits/stdc++.h>
using namespace std ;
int n,m;
const int maxn = 1e6+3;
vector<pair<int,int> >G[maxn];
int pre[maxn],fa[maxn][19],dep[maxn],mx[maxn][19],ans[maxn];
struct no
{
int id,u,v,w;
}a[maxn];
bool cmp(no a , no b)
{
return a.w<b.w;
}
int find(int x)
{
if(pre[x]==x) return x;
pre[x]=find(pre[x]);
return pre[x];
}
void dfs(int u , int p)
{
for(int i=0 ; i<G[u].size() ; i++)
{
int v=G[u][i].first;
if(p==v) continue;
dep[v]=dep[u]+1;
fa[v][0]=u;
mx[v][0]=G[u][i].second;
dfs(v,u);
}
}
int lca(int u , int v)
{
if(dep[u]>dep[v]) swap(u,v);
for(int i=0 ; i<18 ; i++)
if((dep[v]-dep[u])&(1<<i)) v=fa[v][i];
if(u==v) return u;
for(int i=17 ; i>=0 ; i--)
if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
//int ask(int u , int st)
//{
// int ret=0;
// for(int i=0 ; i<18 ; i++)
// if(st&(1<<i))
// {
// ret=max(ret,mx[u][i]);
// u=fa[u][i];
// }
// return ret;
//}
int find_maxw(int x, int y)
{
int c=lca(x,y);
int ret=0;
for(int i=17;i>=0;i--)
{
if(dep[fa[x][i]]>=dep[c])
{
ret=max(ret,mx[x][i]);
x=fa[x][i];
}
}
for(int i=17;i>=0;i--)
{
if(dep[fa[y][i]]>=dep[c])
{
ret=max(ret,mx[y][i]);
y=fa[y][i];
}
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0 ; i<m ; i++)
{
a[i].id=i;
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
}
///卡鲁思
for(int i=1 ; i<=n ; i++) pre[i]=i;
sort(a,a+m,cmp);
for(int i=0 ; i<m ; i++)
{
int u=find(a[i].u) ;
int v=find(a[i].v);
if(u!=v)
{
pre[u]=v;
ans[a[i].id]=-1;//被标记说明原先是在最小生成树上的,不是要被处理的边
G[a[i].u].push_back({a[i].v,a[i].w});
G[a[i].v].push_back({a[i].u,a[i].w});
}
}
///lca
dep[1]=1;
dfs(1,0);
for(int i=1 ; i<18 ; i++)
for(int j=1 ; j<=n ; j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
mx[j][i]=max(mx[j][i-1],mx[fa[j][i-1]][i-1]);//记录边权值
}
for(int i=0 ; i<m ; i++)
if(ans[a[i].id]!=-1)
{
int u=a[i].u ,v=a[i].v;
ans[a[i].id]=find_maxw(u,v);
//ans[a[i].id]=max(ask(u,dep[u]-dep[w]),ask(v,dep[v]-dep[w]));
}
for(int i=0 ; i<m ; i++)
{
if(ans[i]!=-1)
printf("%d ",ans[i]);
}
}
京公网安备 11010502036488号