给定一张无向图,求严格次小的生成树(保证存在)
非严格次小的很好做
kruskal求出最小生成树,倍增求LCA与区间最大边权
枚举剩下的边两端点之间的最大值比较即可.
但是要严格次小的话,要在倍增时维护一个次大边权值
枚举时如果当前边与最大相等则比较次大
做的时候一堆奇怪的bug。。
#include <bits/stdc++.h> #define LL long long using namespace std; const int N=100004,M=300005; struct Edge{ int u,v,nex,flag;LL w; }e[M*2],edge[M*2]; int n,m,tot,head[N],fa[N][20],dep[N],pa[N]; LL ma[N][20],m2[N][20],sum; inline void Addedge(int u,int v,LL w) { edge[++tot].v=v;edge[tot].nex=head[u];edge[tot].w=w;head[u]=tot; } bool cmp(const Edge &a,const Edge &b) { return a.w<b.w; } int find(int v) { if(pa[v]==v)return v; return pa[v]=find(pa[v]); } void kruskal() { int cnt=0; sort(e+1,e+m+1,cmp); for(int i=1;i<=n;i++)pa[i]=i; for(int i=1;i<=m;i++) { if(cnt==n-1)break; int x=find(e[i].u),y=find(e[i].v); if(x!=y){ pa[x]=y;sum+=e[i].w;cnt++; Addedge(e[i].u,e[i].v,e[i].w); Addedge(e[i].v,e[i].u,e[i].w); e[i].flag=1; //e[i].nex=head[e[i].u];head[e[i].u]=i; } } } void dfs(int u,int f) { for(int i=1;i<=19;i++){ int ff=fa[u][i-1]; fa[u][i]=fa[ff][i-1]; ma[u][i]=max(ma[u][i-1],ma[ff][i-1]); //m2[u][i]=getsec(ma[u][i-1],m2[u][i-1],ma[ff][i-1],m2[ff][i-1]); m2[u][i]=max(m2[u][i-1],m2[ff][i-1]); if(ma[u][i-1]!=ma[ff][i-1]) m2[u][i]=max(m2[u][i],min(ma[u][i-1],ma[ff][i-1])); } for(int i=head[u];i;i=edge[i].nex){ int v=edge[i].v,w=edge[i].w; if(v==f)continue; fa[v][0]=u;ma[v][0]=w;dep[v]=dep[u]+1; dfs(v,u); } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=19;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y)return x; for(int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } LL ans=(1LL<<40); void cal(int x,int lca,LL v) { LL c1=0,c2=0; int h=dep[x]-dep[lca]; for(int i=19;i>=0;i--)if(h&(1<<i)) { if(ma[x][i]>c1) c2=c1,c1=ma[x][i]; c2=max(c2,m2[x][i]); h-=(1<<i); } if(v==c1)ans=min(ans,v-c2); else ans=min(ans,v-c1); } void ask(int x,int y,LL len) { int lca=LCA(x,y); cal(x,lca,len);cal(y,lca,len); } int main() { scanf("%d%d",&n,&m); for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w); } kruskal(); dfs(1,0); for(int i=1;i<=m;i++) { if(e[i].flag)continue; ask(e[i].u,e[i].v,e[i].w); } printf("%lld\n",sum+ans); return 0; }