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

Posted popo-black-cat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4180 模板严格次小生成树[BJWC2010]相关的知识,希望对你有一定的参考价值。

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

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

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

  如果新加的边 > 这条路径上最大值,则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
",ans);
}
main()
{
    scanf("%lld%lld",&n,&m);
    //if(n==7) {printf("242
");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
",k[i].w,in[k[i].id]);
    dfs(1,0);
    SEC_Kruscal();
    //cout<<s[3][0]<<endl;
    return 0;
}

 

以上是关于P4180 模板严格次小生成树[BJWC2010]的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P4180 模板严格次小生成树[BJWC2010]次小生成树

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

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

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

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

P4180 严格次小生成树[BJWC2010]