严格次小生成树

    科技2022-08-04  103

    文章目录

    思路证明 代码

    题目传送门

    思路

    我们首先求出最小生成树,可知次小生成树与最小生成树只有一边之差(恶心)。

    证明

    我们先求一个最小生成树。 然后,我们加入一条没有使用过的边加入,就会形成一个环。 我们设这个环上最大值为 V a l 1 Val_1 Val1,次大值为 V a l 2 Val_2 Val2。 所以我们 V a l 1 > V a l 2 Val_1>Val_2 Val1>Val2。 我们将加入的边替换掉 V a l 1 Val_1 Val1

    ans=ans-val1+z;

    其中 z z z为多余边。

    但当我们的 V a l 1 Val_1 Val1等于加入的边时,我们就要替换 V a l 1 Val_1 Val1不是答案,我们就要替换 V a l 2 Val_2 Val2。 我们将加入的边替换掉 V a l 2 Val_2 Val2

    ans=ans-val2+z;

    我们把得出的值求出最小值就可以了。

    但我们有一个很严肃的问题:我们这么求最小值和次小值?

    我们就使用 L C A LCA LCA来计算路径上的最大值和次大值。

    代码

    #include <bits/stdc++.h> using namespace std; int n,m,fa[100005],head[100005],ver[200005],edge[200005],next[200005],cnt,ans=0x3f3f3f3f; long long sum; struct node{ int u,v,w; bool flag; node(){ flag=u=v=w=0; } bool operator <(const node &x) const { return w<x.w; } }a[300005]; int find(int x) { if(fa[x]==x) return fa[x]; return fa[x]=find(fa[x]); } void add_edge(int u,int v,int w) { ver[++cnt]=v,edge[cnt]=w,next[cnt]=head[u],head[u]=cnt; } void Kurskal() { int k=1; for(int i=1;i<=n;i++) fa[i]=i; sort(a+1,a+m+1); for(int i=1;k<n;i++) { int s1=find(a[i].u),s2=find(a[i].v); if(s1!=s2) { fa[s1]=s2; a[i].flag=1; add_edge(a[i].u,a[i].v,a[i].w),add_edge(a[i].v,a[i].u,a[i].w); k++,sum+=a[i].w; } } return ; } int dep[100005],f[100005][25],maxx[100005][25],smax[100005][25]; void dfs(int x) { for(int i=0;f[x][i];i++) { f[x][i+1]=f[f[x][i]][i]; maxx[x][i+1]=max(maxx[x][i],maxx[f[x][i]][i]); if(maxx[x][i]==maxx[f[x][i]][i]) smax[x][i+1]=max(smax[x][i],smax[f[x][i]][i]); else smax[x][i+1]=max(min(maxx[x][i],maxx[f[x][i]][i]),max(smax[x][i],smax[f[x][i]][i])); } for(int i=head[x];i;i=next[i]) { int v=ver[i]; if(v!=f[x][0]) { dep[v]=dep[x]+1,maxx[v][0]=edge[i],smax[v][0]=-1,f[v][0]=x; dfs(v); } } return ; } int LCA(int a,int b){ if(dep[a]<dep[b]) swap(a,b); int d=dep[a]-dep[b]; for(int i=0;d;i++,d>>=1) if(d & 1) a=f[a][i]; if(a==b) return a; for(int i=20;i>=0;i--) if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i]; return f[a][0]; } void work(int u,int v,int w) { int d=dep[u]-dep[v]; int m1=0,m2=0; for(int i=0;d;i++,d>>=1) { if(d & 1) { m2=max(m2,smax[u][i]); if(maxx[u][i]>m1) { m2=max(m2,m1); m1=maxx[u][i]; } } } if(m1==w) ans=min(ans,w-m2); else ans=min(ans,w-m1); } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) scanf("%d %d %d",&a[i].u,&a[i].v,&a[i].w); Kurskal(); dfs(1); for(int i=1;i<=m;i++) { if(a[i].flag) continue; int u=a[i].u,v=a[i].v; int lca=LCA(u,v); work(u,lca,a[i].w),work(v,lca,a[i].w); } printf("%lld",sum+ans); return 0; }
    Processed: 0.040, SQL: 8