码迷,mamicode.com
首页 > 其他好文 > 详细

【总结】 (严格)次小生成树

时间:2018-10-31 01:17:33      阅读:696      评论:0      收藏:0      [点我收藏+]

标签:oid   更新   sign   min   include   dfs   front   clu   for   

前言

首先需要了解什么是最小生成树,还要知道什么是倍增(求Lca).

上面的东西如果了解了,就可以开始进入学习的路途了!!

1 算法框架

1.1 整体思路

用不是最小生成树上的边去更新答案.

1.2 具体维护

对于每一个倍增跳上去的,要维护两个东西:

  • 路径的边权最大值.
  • 路径的边权次大值

2 具体实现

我们考虑一下对于每一条边(不在最小生成树上),如果要把它加入答案,如何更新?

MST-路径最大值+边权.

然后这个东西就可以很愉快地解决了...

其实不是的,如果题目求的是次小生成树,这题就没了,但是题目要求的是严格次小生成树,怎么办呢?

考虑一下,如果要这样子,我们更新答案就不能和MST相等,然后依旧可以很愉快地解决了!!!

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define int long long
const int N=100010,M=300010,Inf=2e18+10;
struct node{
    int u,v,w;
}e[M];
int fa[N],front[N],to[N<<1],nxt[N<<1],w[N<<1],MST,cnt,n,m,k,flag[M];
int f[N][20],Min[N][20],Max[N][20],dep[N];
int find(int x){
    if(fa[x]!=x)fa[x]=find(fa[x]);
    return fa[x];
}
void Add(int u,int v,int W){
    to[++cnt]=v;nxt[cnt]=front[u];w[cnt]=W;
    front[u]=cnt;
}
bool cmp(node a,node b){
    return a.w<b.w;
}
void dfs(int u,int Fa){
    f[u][0]=Fa;
    for(int i=front[u];i;i=nxt[i]){
        int v=to[i];
        if(v!=Fa){
            dep[v]=dep[u]+1ll;
            Max[v][0]=w[i];
            Min[v][0]=-Inf;
            dfs(v,u);
        }
    }
}
int LCA(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    for(int i=18;~i;i--)
        if(dep[f[u][i]]>=dep[v])
            u=f[u][i];
    if(u==v)return u;
    for(int i=18;~i;i--)
        if(f[u][i]!=f[v][i])
            u=f[u][i],v=f[v][i];
    return f[u][0];
}
int qmax(int u,int v,int W){
    int ans=-Inf;
    for(int i=18;~i;i--)
        if(dep[f[u][i]]>=dep[v]){
            if(W!=Max[u][i])ans=max(ans,Max[u][i]);
            else ans=max(ans,Min[u][i]);
            u=f[u][i];
        }
    return ans;
}
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int u,v,W;scanf("%lld%lld%lld",&u,&v,&W);
        e[i]=(node){u,v,W};
    }
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++){
        int u=find(e[i].u),v=find(e[i].v);
        if(u!=v){
            flag[i]=1;
            Add(e[i].u,e[i].v,e[i].w);
            Add(e[i].v,e[i].u,e[i].w);
            fa[v]=u;MST+=e[i].w;
            k++;if(k==n-1)break;
        }
    }
    Min[1][0]=-Inf;
    dep[1]=1;
    dfs(1,-1);
    for(int j=1;j<=18;j++)
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            Max[i][j]=max(Max[i][j-1],Max[f[i][j-1]][j-1]);
            Min[i][j]=max(Min[i][j-1],Min[f[i][j-1]][j-1]);
            if(Max[i][j-1]>Max[f[i][j-1]][j-1])
                Min[i][j]=max(Min[i][j],Max[f[i][j-1]][j-1]);
            else if(Max[i][j-1]<Max[f[i][j-1]][j-1])
                Min[i][j]=max(Min[i][j],Max[i][j-1]);
        }
    int ans=Inf;
    for(int i=1;i<=m;i++)
        if(!flag[i]){
            int u=e[i].u,v=e[i].v;
            int lca=LCA(u,v);
            int Maxu=qmax(u,lca,e[i].w),Maxv=qmax(v,lca,e[i].w);
            ans=min(ans,MST-max(Maxu,Maxv)+e[i].w);
        }
    printf("%lld\n",ans);
    return 0;
}

【总结】 (严格)次小生成树

标签:oid   更新   sign   min   include   dfs   front   clu   for   

原文地址:https://www.cnblogs.com/biscuit46/p/9880303.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!