题目大意:给定一个无向图,求严格次小生成树
这题纠结了我同学很久。。。首先如果是不严格的次小生成树(权值可以等于最小生成树),那么我们就有一个很简单明了的算法:
首先求出最小生成树 然后建立倍增LCA 枚举没进入最小生成树的边 在边的两端点的路径上寻找最大的边权 用最小生成树权值-最大边权+新边权去更新ans即可
但是这道题是严格次小生成树 那么也好办 我们记录一个次大边权 如果枚举到的边权和最大边权相等 就用路径上的次大边权代替最大边权去更新即可
于是我们只需要在倍增的时候记录最大权值和次大权值即可 注意建立倍增LCA的时候次大值的讨论 这里容易出问题
假期被罚十道题第一道。。。苦逼的娃,同学们都刷了四道了0.0 10%达成
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef long long ll;
struct edge{
int x,y,f;
bool used;
bool operator < (const edge &y) const
{
return f < y.f;
}
}edges[300300];
struct abcd{
int to,f,next;
}table[M<<1];
int head[M],tot;
int n,m,fa[M][20],f_max[M][20],f_2th_max[M][20],dpt[M];
ll ans_min,ans_2th_min=~0ull>>1;
int belong[M];
int find(int x)
{
if(!belong[x]||belong[x]==x) return belong[x]=x;
return belong[x]=find(belong[x]);
}
void add(int x,int y,int z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
void dfs(int x)
{
int i;
dpt[x]=dpt[fa[x][0]]+1;
for(i=head[x];i;i=table[i].next)
{
if(table[i].to==fa[x][0])
continue;
fa[table[i].to][0]=x;
f_max[table[i].to][0]=table[i].f;
dfs(table[i].to);
}
}
int Find_F_Max(int x,int y)
{
int j,re=0;
if(dpt[x]<dpt[y])
swap(x,y);
for(j=19;~j;j--)
if(dpt[fa[x][j]]>=dpt[y])
re=max(re,f_max[x][j]),x=fa[x][j];
if(x==y)
return re;
for(j=19;~j;j--)
if(fa[x][j]!=fa[y][j])
{
re=max(re,f_max[x][j]);
re=max(re,f_max[y][j]);
x=fa[x][j];
y=fa[y][j];
}
re=max(re,f_max[x][0]);
re=max(re,f_max[y][0]);
return re;
}
int Find_F_2th_Max(int x,int y,int z)
{
int j,re=0;
if(dpt[x]<dpt[y])
swap(x,y);
for(j=19;~j;j--)
if(dpt[fa[x][j]]>=dpt[y])
{
if(f_max[x][j]!=z)
re=max(re,f_max[x][j]);
else
re=max(re,f_2th_max[x][j]);
x=fa[x][j];
}
if(x==y)
return re;
for(j=19;~j;j--)
if(fa[x][j]!=fa[y][j])
{
if(f_max[x][j]!=z)
re=max(re,f_max[x][j]);
else
re=max(re,f_2th_max[x][j]);
if(f_max[y][j]!=z)
re=max(re,f_max[y][j]);
else
re=max(re,f_2th_max[y][j]);
x=fa[x][j];
y=fa[y][j];
}
j=0;
if(f_max[x][j]!=z)
re=max(re,f_max[x][j]);
else
re=max(re,f_2th_max[x][j]);
if(f_max[y][j]!=z)
re=max(re,f_max[y][j]);
else
re=max(re,f_2th_max[y][j]);
return re;
}
int main()
{
int i,j;
cin>>n>>m;
for(i=1;i<=m;i++)
scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f);
sort(edges+1,edges+m+1);
for(i=1;i<=m;i++)
{
int fx=find(edges[i].x),fy=find(edges[i].y);
if(fx!=fy)
{
edges[i].used=true;
belong[fx]=fy;
ans_min+=edges[i].f;
add(edges[i].x,edges[i].y,edges[i].f);
add(edges[i].y,edges[i].x,edges[i].f);
}
}
dfs(1);
for(j=1;j<=19;j++)
for(i=1;i<=n;i++)
{
int f=fa[i][j-1];
fa[i][j]=fa[f][j-1];
if( f_max[i][j-1] > f_max[f][j-1] )
{
f_max[i][j]=f_max[i][j-1];
f_2th_max[i][j]=max( f_2th_max[i][j-1] , f_max[f][j-1] );
}
else
{
f_max[i][j]=f_max[f][j-1];
if( f_max[i][j-1] < f_max[f][j-1] )
f_2th_max[i][j]=max( f_2th_max[f][j-1] , f_max[i][j-1] );
else
f_2th_max[i][j]=max( f_2th_max[i][j-1] , f_2th_max[f][j-1] );
}
f_max[i][j]=max( f_max[i][j-1] , f_max[f][j-1] );
}
for(i=1;i<=m;i++)
if(!edges[i].used)
{
int temp=Find_F_Max(edges[i].x,edges[i].y);
if(temp==edges[i].f)
temp=Find_F_2th_Max(edges[i].x,edges[i].y,temp);
ans_2th_min=min(ans_2th_min,ans_min-temp+edges[i].f);
}
cout<<ans_2th_min<<endl;
}