洛谷4180 BZOJ1977 严格次小生成树 学习笔记

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/82465819

题目链接
题意:求一个图的严格次小生成树

题解:
首先求出最小生成树,并且标记所有在最小生成树上的边。然后考虑枚举每一条不在最小生成树上的边,如果它连接了x与y,那么在树上x到lca(x,y)到y的位置就会形成了一个环,那么我们找到这一部分的严格小于当前要加入生成树的边中最大的一条,我们就把那条换成当前边,然后尝试更新答案,维护的话只需要规定一号点是根,然后维护树上每个点向上 2 i 个点中的边的最大值和严格次大值,用st表记录即可,所以需要用倍增LCA就行了。

代码:

#include <bits/stdc++.h>
using namespace std;

int n,m,fa[200010],f[200010],book[300010],hed[300010],cnt;
int dep[400010],bz[400010][20];
long long ans,res,zui[400010][21],ci[400010][21];
struct node
{
    int x,y;
    long long dis;
}e[300010];
struct edge
{
    int to,next;
    long long dis;
}a[600010];
inline int cmp(node x,node y)
{
    return x.dis<y.dis;
}
inline int getr(int x)
{
    if(x==f[x])
    return x;
    else
    {
        f[x]=getr(f[x]);
        return f[x];
    }
}
inline void add(int from,int to,long long dis)
{
    a[++cnt].to=to;
    a[cnt].dis=dis;
    a[cnt].next=hed[from];
    hed[from]=cnt;
    a[++cnt].to=from;
    a[cnt].dis=dis;
    a[cnt].next=hed[to];
    hed[to]=cnt;
}
inline void dfs(int x)
{
    bz[x][0]=fa[x];
    for(int i=hed[x];i;i=a[i].next)
    {
        int y=a[i].to;
        if(y==fa[x])
        continue;
        fa[y]=x;
        dep[y]=dep[x]+1;
        zui[y][0]=a[i].dis;
        ci[y][0]=-2e18;
        dfs(y);
    }
}
inline void cal()
{
    for(int i=1;i<=18;++i)
    {
        for(int j=1;j<=n;++j)
        {
            bz[j][i]=bz[bz[j][i-1]][i-1];
            zui[j][i]=max(zui[j][i-1],zui[bz[j][i-1]][i-1]);
            ci[j][i]=max(ci[j][i-1],ci[bz[j][i-1]][i-1]);
            if(zui[j][i-1]>zui[bz[j][i-1]][i-1])
            ci[j][i]=max(ci[j][i],zui[bz[j][i-1]][i-1]);
            else if(zui[j][i-1]<zui[bz[j][i-1]][i-1])
            ci[j][i]=max(ci[j][i],zui[j][i-1]);
        }
    }
}
inline int lca(int x,int y)
{
    if(dep[x]<dep[y])
    swap(x,y);
    for(int i=18;i>=0;--i)
    {
        if(dep[bz[x][i]]>=dep[y])
        x=bz[x][i];
    }
    if(x==y)
    return x;
    for(int i=18;i>=0;--i)
    {
        if(dep[x]>=(1<<i)&&bz[x][i]!=bz[y][i])
        {
            x=bz[x][i];
            y=bz[y][i];
        }
    }
    return bz[x][0]; 
}
inline long long query(int x,int y,long long z)
{
    long long ji=-2e18;
    for(int i=18;i>=0;--i)
    {
        if(dep[bz[x][i]]>=dep[y])
        {
            if(zui[x][i]!=z)
            ji=max(ji,zui[x][i]);
            else
            ji=max(ji,ci[x][i]);
            x=bz[x][i];
        }
    }
    return ji;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    scanf("%d%d%lld",&e[i].x,&e[i].y,&e[i].dis);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=n;++i)
    f[i]=i;
    for(int i=1;i<=m;++i)
    {
        int rx=getr(e[i].x),ry=getr(e[i].y);
        if(rx!=ry)
        {
            f[rx]=ry;
            ans+=e[i].dis;
            book[i]=1;
            add(e[i].x,e[i].y,e[i].dis);
        }
    }
    dep[1]=1;
    ci[1][0]=-2e18;
    dfs(1);
    cal();
    res=2e18;
    for(int i=1;i<=m;++i)
    {
        if(!book[i])
        {
            long long x=lca(e[i].x,e[i].y),maxn;
            maxn=query(e[i].x,x,e[i].dis);
            maxn=max(maxn,query(e[i].y,x,e[i].dis));
            res=min(res,ans-maxn+e[i].dis);
        }
    }
    printf("%lld\n",res);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/82465819