题目描述
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) ∑ e ∈ E M v a l u e ( e ) < ∑ e ∈ E S v a l u e ( e ) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e) ∑e∈EMvalue(e)<∑e∈ESvalue(e)
这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
输入格式
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
输出格式
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
输入输出样例
输入 #1
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
输出 #1
11
说明/提示
数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
typedef pair<ll,ll> pii;
template<class T>ll chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>ll chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
ll read(){
ll s=0,base=1;
char c;
while(!isdigit(c=getchar()))if(c=='-')base=-base;
while(isdigit(c)){s=s*10+(c^48);c=getchar();}
return s*base;
}
char WritellBuffer[1024];
template<class T>void write(T a,char end){
ll cnt=0,fu=1;
if(a<0){putchar('-');fu=-1;}
do{WritellBuffer[++cnt]=fu*(a%10)+'0';a/=10;}while(a);
while(cnt){putchar(WritellBuffer[cnt]);--cnt;}
putchar(end);
}
struct edge{
ll u,v,w;
};
edge e[333333];
ll fa[102424],use[333333];
ll beg[102424],to[204848],lst[204848],w[204848],dis[102424],en;
ll f[102424][20],mx1[102424][20],mx2[102424][20];
ll e_cmp(edge a,edge b){
return a.w<b.w;
}
ll find(ll x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void add(ll u,ll v,ll wa){
to[++en]=v;
lst[en]=beg[u];
beg[u]=en;
w[en]=wa;
}
void dfs(ll x,ll fa){
f[x][0]=fa;
dis[x]=dis[fa]+1;
for(ll i=beg[x];i;i=lst[i])if(to[i]!=fa){
dfs(to[i],x);
}
else mx1[x][0]=w[i];
}
void upd(ll &mx1,ll &mx2,ll mxx1,ll mxx2){
ll nm=max(mx1,mxx1),inm=0;
if(mx1==nm)chkmax(inm,mx2);
else chkmax(inm,mx1);
if(mxx1==nm)chkmax(inm,mxx2);
else chkmax(inm,mxx1);
mx1=nm;
mx2=inm;
}
void build(ll n,ll t){
for(ll j=1;j<=t;++j)for(ll i=1;i<=n;++i){
f[i][j]=f[f[i][j-1]][j-1];
mx1[i][j]=mx1[i][j-1];
mx2[i][j]=mx2[i][j-1];
upd(mx1[i][j],mx2[i][j],mx1[f[i][j-1]][j-1],mx2[f[i][j-1]][j-1]);
}
}
ll _lca(edge e){
ll u=e.u,v=e.v,w=e.w,max1=0,max2=0;
if(dis[u]<dis[v])swap(u,v);
for(ll i=18;~i;--i){
if(dis[u]-(1<<i)>=dis[v]){
upd(max1,max2,mx1[u][i],mx2[u][i]);
u=f[u][i];
}
}
for(ll i=18;~i;--i){
if(f[u][i]!=f[v][i]){
upd(max1,max2,mx1[u][i],mx2[u][i]);
upd(max1,max2,mx1[v][i],mx2[v][i]);
u=f[u][i];
v=f[v][i];
}
}
if(u!=v){
ll i=0;
upd(max1,max2,mx1[u][i],mx2[u][i]);
upd(max1,max2,mx1[v][i],mx2[v][i]);
u=f[u][i];
v=f[v][i];
}
if(max1==w)if(max2)return w-max2;else return 0x3f3f3f3f3f3f3f3f;
else return w-max1;
}
int main(){
ll n,m;
n=read();m=read();
for(ll i=1;i<=m;++i){
e[i].u=read();
e[i].v=read();
e[i].w=read();
}
sort(e+1,e+m+1,e_cmp);
for(ll i=1;i<=n;++i)fa[i]=i;
ll q=n;
ll sum=0,ans=0x3f3f3f3f3f3f3f3f;
for(ll i=1;q>1;++i)if(find(e[i].u)!=find(e[i].v)){
add(e[i].v,e[i].u,e[i].w);
add(e[i].u,e[i].v,e[i].w);
sum+=e[i].w;
fa[find(e[i].u)]=find(e[i].v);
use[i]=1;
--q;
}
dfs(1,0);
build(n,18);
for(ll i=1;i<=m;++i)if(!use[i]){
chkmin(ans,sum+_lca(e[i]));
}
printf("%lld\n",ans);
return 0;
}