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

P4180 【模板】严格次小生成树[BJWC2010]

时间:2019-04-10 23:43:36      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:一个   最大值   严格   algo   dea   span   最小   ec2   生成树   

  之前写的一道题,突然看到就来发一篇博客。

  大致思路就是首先找到最小生成树,再枚举每一条不在这个树里的边,加上后肯定就形成一个环,我们就要在这个环上断一条边。

  新加的边 >= 这条路径上最大值。(反证法)

  如果新加的边 > 这条路径上最大值,则ans - 最大值 + 新的权值,否则 - 次大值 + 新的值。

  因此我们需要维护最大值,次大值即可。  

  以及,我的代码并不支持重边,提前筛掉。

  下面是代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define maxn 200010
#define inf 9999999999999999
int f[maxn][25],M[maxn][25],s[maxn][25],head[maxn];
int fa[maxn],dep[maxn],in[maxn*6],o[maxn];
int n,m,cnt,tot,MAX,SEC_MAX,ans=inf,size,map[1000][1000];
struct node
{
    int to,nxt,w;
} q[maxn*2];
struct K
{
    int l,r,w,id;
} k[maxn*6];
int find(int a)
{
    return a==fa[a] ? a : fa[a]=find(fa[a]);
}
void add(int a,int b,int c)
{
    q[++cnt].to=b;
    q[cnt].nxt=head[a];
    head[a]=cnt;
    q[cnt].w=c;
}
bool cmp(K a,K b)
{
    return a.w<b.w;
}
void Kruscal()
{
    int num=0;
    for(int i=1; i<=m; i++)
    {
        int L=k[i].l;
        int R=k[i].r;
        int faL=find(L);
        int faR=find(R);
        if(faL==faR) continue;
        num++;
        fa[faL]=faR;
        add(k[i].l,k[i].r,k[i].w);
        add(k[i].r,k[i].l,k[i].w);
        in[k[i].id]=1;
        size+=k[i].w;
        if(num==n-1) break;
    }
}
void dfs(int u,int ff)
{
    //cout<<u<<endl;
    dep[u]=dep[ff]+1;
    for(int i=0; i<=20; i++)
    {
        f[u][i+1]=f[f[u][i]][i];
        M[u][i+1]=max(M[u][i],M[f[u][i]][i]);
        int sec1=min(M[u][i],M[f[u][i]][i]);
        int sec2=max(s[u][i],s[f[u][i]][i]);
        s[u][i+1]=max(sec1,sec2);
    }
    for(int i=head[u]; i; i=q[i].nxt)
    {
        int v=q[i].to;
        if(v==ff) continue;
        M[v][0]=q[i].w;
        f[v][0]=u;
        dfs(v,u);
    }
}
void Deal(int x,int i)
{
    if(MAX!=M[x][i])
    {
        if(MAX<M[x][i])
        {
            SEC_MAX=max(MAX,s[x][i]);
            MAX=M[x][i];
        }
        else
            SEC_MAX=max(SEC_MAX,M[x][i]);
    }
}
void DD(int x)
{
    if(M[x][0]>MAX)
    {
        SEC_MAX=MAX;
        MAX=M[x][0];
    }
    else if(M[x][0]>SEC_MAX)
        SEC_MAX=M[x][0];
}
void LCA(int x,int y)
{
    MAX=SEC_MAX=0;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20; i>=0; i--)
    {
        if(dep[f[x][i]]>=dep[y])
        {
            Deal(x,i);
            x=f[x][i];
        }
        if(x==y) return ;
    }
    for(int i=20; i>=0; i--)
    {
        if(f[x][i]!=f[y][i])
        {
            Deal(x,i);
            Deal(y,i);
            x=f[x][i];
            y=f[y][i];
        }
    }
    //cout<<SEC_MAX<<" "<<MAX<<" ";
    DD(x);
    DD(y);
    return ;
}
void SEC_Kruscal()
{
    for(int i=1; i<=m; i++)
    {
        if(in[k[i].id]) continue;
        int x=k[i].l,y=k[i].r;
        int W=k[i].w;
        LCA(x,y);
        if(W==MAX) ans=min(ans,size-SEC_MAX+W);
        else ans=min(ans,size-MAX+W);
        //cout<<k[i].l<<" "<<k[i].r<<" "<<SEC_MAX<<" "<<MAX<<endl;
    }
    printf("%lld\n",ans);
}
main()
{
    scanf("%lld%lld",&n,&m);
    //if(n==7) {printf("242\n");return 0;}
    for(int i=1; i<=n; i++)
        fa[i]=i;
    for(int i=1; i<=m; i++)
    {
        int a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        k[++tot].l=a;
        k[tot].r=b;
        k[tot].w=c;
        k[tot].id=tot;
    }
    sort(k+1,k+m+1,cmp);
    Kruscal();
    //for(int i=1;i<=m;i++)
    //printf("%d %d\n",k[i].w,in[k[i].id]);
    dfs(1,0);
    SEC_Kruscal();
    //cout<<s[3][0]<<endl;
    return 0;
}

 

P4180 【模板】严格次小生成树[BJWC2010]

标签:一个   最大值   严格   algo   dea   span   最小   ec2   生成树   

原文地址:https://www.cnblogs.com/popo-black-cat/p/10686795.html

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