题意:求严格次小生成树(就是不能等于) 思路:先求一个最小生成树 枚举每条非树边 若连入则一定会成环
那么在这个环中 删去最大的边(除非树边) 就是一个次小生成树
但是如果那个最大边和非树边的值相等 有可能次小生成树的值就和最小生成树一样
显然是不成立的 所以应该记录一下次大值 最大值不满足就用次大值
注意:在dfs中转移的顺序

/*
题意:求严格次小生成树(就是不能等于) 
思路:先求一个最小生成树 枚举每条非树边 若连入则一定会成环
那么在这个环中 删去最大的边(除非树边) 就是一个次小生成树
但是如果那个最大边和非树边的值相等 有可能次小生成树的值就和最小生成树一样
显然是不成立的 所以应该记录一下次大值 最大值不满足就用次大值
注意:在dfs中转移的顺序 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define ll long long
struct node{
    int x,y,in; int w;
}a[N*3];
int fa[N],head[N<<1],nex[N<<1],to[N<<1],tot=0,f[N][22],dep[N];
int d1[N][22],d2[N][22],w[N<<1],mn=0x7f7f7f;
bool cmp(const node &a,const node &b) { return a.w<b.w; }
int get(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=get(fa[x]);
}
void add(int a,int b,int ww){ to[++tot]=b; nex[tot]=head[a]; head[a]=tot; w[tot]=ww;}
void dfs(int u,int father)
{//倍增的初始化一定要在for的外面!! 
    for(int i=1;i<=20;i++){
        f[u][i]=f[f[u][i-1]][i-1];
        //d1是最大值 d2是次大值 
        d1[u][i]=max(d1[u][i-1],d1[f[u][i-1]][i-1]);
        if(d1[u][i-1]==d1[f[u][i-1]][i-1])//最大值相等 次大值就是从两段的次大值转移过来 
            d2[u][i]=max(d2[u][i-1],d2[f[u][i-1]][i-1]);
        else{//不相等就可能由两段最大值中的较小值 或 两段次大值 转移过来 
            d2[u][i]=min(d1[u][i-1],d1[f[u][i-1]][i-1]);
            d2[u][i]=max(d2[u][i],d2[u][i-1]);
            d2[u][i]=max(d2[u][i],d2[f[u][i-1]][i-1]);
        }
    }
    for(int j=head[u];j;j=nex[j]){
        int v=to[j];
        if(v==father) continue;
        dep[v]=dep[u]+1; f[v][0]=u; d1[v][0]=w[j];
        dfs(v,u);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--)
    if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}//求路径的最大值和次大值 
void solve(int x,int y,int v)
{
    int mx1=0,mx2=0;
    int t=dep[x]-dep[y];//深度差 是i的范围 
    for(int i=0;i<=20;i++)
    if(t&(1<<i)){//如果还可以跳 
        if(d1[x][i]>mx1) mx2=mx1,mx1=d1[x][i];
        else mx2=max(mx2,d1[x][i]);
        mx2=max(mx2,d2[x][i]);
        x=f[x][i];
    }
    if(mx1!=v) mn=min(mn,v-mx1);
    else mn=min(mn,v-mx2);
}
void work(int x,int y,int ww)
{
    int lc=lca(x,y); 
    solve(x,lc,ww); solve(y,lc,ww);
}
ll ans=0;
int main()
{
    int n,m,cnt=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
    sort(a+1,a+1+m,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++){
        int f1=get(a[i].x),f2=get(a[i].y);
        if(f1!=f2){
            cnt++;
            ans+=a[i].w;
            a[i].in=1;
            fa[f1]=f2;
            add(a[i].x,a[i].y,a[i].w); add(a[i].y,a[i].x,a[i].w);
        }
        if(cnt==n-1) break;
    }
    dfs(1,0);
    for(int i=1;i<=m;i++) if(!a[i].in) work(a[i].x,a[i].y,a[i].w);
    printf("%lld\n",ans+mn);
}
/*
5 6
1 2 1 
1 3 2 
2 4 3 
3 5 4 
3 4 3 
4 5 6 
*/

 

posted on 2019-07-11 16:47  rua-rua-rua  阅读(164)  评论(0编辑  收藏  举报