严格次小生成树


1555:【例 4】次小生成树

 这次是在图里面求严格次小生成树

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+10;
const int M=3e5+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
/*
https://blog.csdn.net/regina8023/article/details/44814899
https://blog.csdn.net/YYHS_WSF/article/details/82842355
求出最小生成树,枚举每一条非树边,用它取代掉环上最大的边最优。
那么相当于求两点到lca的最大边权,直接倍增做。
但是要注意是严格最小生成树,那么这条非树边与环上最大边相同时可能取代掉的是环上的次大边,那么倍增的时候多维护一个严格次大的边即可。
*/
int n,m;
struct node{
    int u,v,wei;
}ed[M];
queue q;
struct edge{
    int to,next,w;
}e[M*2];
struct ma{
    int a,b;  //分别是 最大、次大
}g[maxn][21],p;
int head[maxn],dep[maxn],f[maxn][21],fa[maxn];  //后两个:深度,倍增数组
int vis[M];
bool cmp(node a,node b){
    return a.weiy.a) x.b=max(y.a,x.b);   //b记录的是次大  ,这三行都是在更新次大
    else if(x.a=0;i--){
        if(dep[f[x][i]]>=deep) {
            updat(p,g[x][i]);
            x=f[x][i];
        }
    }
}
void getlca(int x,int y){
    p.a=p.b=-INF;
    if(dep[x]>dep[y]) swap(x,y);
    mov(y,dep[x]);  //先移动到同一层
    if(x==y) return;
    for(int i=20;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            updat(p,g[x][i]);
            updat(p,g[y][i]);   //找到替换的那条边严格最大边
            x=f[x][i];
            y=f[y][i];
        }
    }
    updat(p,g[x][0]);
    updat(p,g[y][0]);
     
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d %d",&ed[i].u,&ed[i].v,&ed[i].wei);
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    kru();  //先求出最小生成树的权值
    build();   //用非树边去更新倍增数组,g[][].a  g[][].b
    ST();
    LL ans=(LL)1e15;    //这个要设置的足够大
    for(int i=1;i<=m;i++){
        if(!vis[i]){   //用非树边建立
            getlca(ed[i].u,ed[i].v);
            if(p.a==ed[i].wei){  //最大便与其相等
                ans=min(ans,mst+ed[i].wei-p.b);
            }
            else ans=min(ans,mst+ed[i].wei-p.a);
        }
    }
    printf("%lld\n",ans);
return 0;
}