#include<bits/stdc++.h> #define MAXN 100005 #define MAXM 23 #define EDGE 300005 #define int long long #define INF 0x3f3f3f3f3f3f3f3f usingnamespace std; inlineintread(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=(x<<3)+(x<<1)+(ch^'0'); ch=getchar(); } return x*f; } int anc[MAXN][MAXM],Max1[MAXN][MAXM],Max2[MAXN][MAXM]; //最大值和严格次大值 //Max1[u][i]表示u到u的2^i辈祖先之间边的最大值 //Max2[u][i]表示.....的严格次大值 int n,m; structEdge{ int to,len; }; vector<Edge>G[MAXN]; inlinevoidAddEdge(int u,int v,int w){ G[u].push_back(Edge{v,w}); }
//--------------------Kruscal structEdge1{ int u,v,w; }e[EDGE]; inlinebooloperator < (const Edge1 &A,const Edge1 &B){ return A.w<B.w; } namespace BCJ{ int fa[MAXN]; inlinevoidInit_BCJ(){ for (registerint i=0;i<MAXN;++i) fa[i]=i; } intFa(int i){ return fa[i]==i?i:fa[i]=Fa(fa[i]); } } usingnamespace BCJ; int MST[EDGE];//是否出现在最小生成树中 inlineintKruscal(){ Init_BCJ(); sort(e+1,e+1+m); int mst=0; for (registerint i=1;i<=m;++i){ int u=e[i].u,v=e[i].v,w=e[i].w; int fau=Fa(u),fav=Fa(v); if (fau!=fav){ fa[fau]=fav; mst+=w; MST[i]=true; AddEdge(u,v,w); AddEdge(v,u,w); } } return mst; } //---------------------------- int dep[MAXN]; voiddfs(int u,int father){ anc[u][0]=father; for (registerint i=0;i<G[u].size();++i){ int v=G[u][i].to,w=G[u][i].len; if (v!=father){ Max1[v][0]=w; Max2[v][0]=-INF;//不存在次大值 dep[v]=dep[u]+1; dfs(v,u); } } } inlinevoidMerge(int &max1,int &max2,int max1d,int max1u,int max2d,int max2u){ max1=max(max1d,max1u); if (max1d>max1u) max2=max(max2d,max1u); elseif (max1d==max1u) max2=max(max2d,max2u); else max2=max(max1d,max2u); } inlinevoidInit(){ for (registerint i=1;i<MAXM;++i){ for (registerint u=1;u<=n;++u){ anc[u][i]=anc[anc[u][i-1]][i-1]; Merge(Max1[u][i],Max2[u][i],Max1[u][i-1],Max1[anc[u][i-1]][i-1],Max2[u][i-1],Max2[anc[u][i-1]][i-1]); } } } inlineintLCA(int u,int v){ if (u==1||v==1) return1; if (dep[u]<dep[v]) swap(u,v); for (registerint i=MAXM-1;i>=0;--i){ if (dep[anc[u][i]]>=dep[v]){ u=anc[u][i]; } } if (u==v) return u; for (registerint i=MAXM-1;i>=0;--i){ if (anc[u][i]!=anc[v][i]){ u=anc[u][i],v=anc[v][i]; } } return anc[u][0]; } inlineintHop(int u,int lca,int val){ int maxn=-INF;//次大值!=val for (registerint i=MAXM-1;i>=0;--i){ if (dep[anc[u][i]]>=dep[lca]){//I can H♂p if (Max1[u][i]!=val) maxn=max(maxn,Max1[u][i]);//这样可以采用最大值 else maxn=max(maxn,Max2[u][i]);//不能采用最大值,要不然就不是严格次大生成树了,所以只能采用严格次大值 u=anc[u][i]; } } return maxn; } #undef int intmain(){ #define int long long n=read(),m=read(); for (registerint i=1;i<=m;++i){ e[i].u=read();e[i].v=read();e[i].w=read(); } int mst=Kruscal(); dfs(1,1); Init(); int ans=INF; for (registerint i=1;i<=m;++i){ if (!MST[i]){ int u=e[i].u,v=e[i].v,w=e[i].w; int lca=LCA(u,v); int len=max(Hop(u,lca,w),Hop(v,lca,w)); ans=min(ans,mst+w-len);//减去len这条边,加上w这条边 } } printf("%lld\n",ans); }