【模板】严格次小生成树

严格次小生成树[BJWC2010]

是无意间脑残点开的一道题目。。。呜。。。

(1e4+7写不起紫题系列)

\(LCA+Kruscal\)。先求一遍\(mst\),再遍历不在最小生成树里的每一条边。加入生成树&删除原树一条边。

删除的边::原树上这两点的路径上的最大边。必须计算这条边上(严格的!)次大值,如果最大值和加入的边权值相等就换为次大边。

然后找出最小策略。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define MAXN 300000
#define inf 0x7fffffff
using namespace std;

int n,m,cnt=0,tot=0;
struct data
{
    int x,y,val;
    bool book;
}a[MAXN];
struct edge
{
    int next,to,v;
}e[MAXN<<1];
int amn=inf;
long long ans=0;
int f[MAXN],head[MAXN],deep[MAXN],fa[MAXN][17],adp[MAXN][17],bdp[MAXN][17];
bool cmp(data x,data y)
{
    return x.val<y.val;
}
void add(int u,int v,int w)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    e[cnt].v=w;
    head[u]=cnt;
}
int find(int x)
{
    if (f[x]==x) return x;
    return f[x]=find(f[x]);
}
void dfs(int x,int ft)
{
    for (int i=1;i<=16;i++)
    {
        if (deep[x]<(1<<i))
        {
            break;
        }
        fa[x][i]=fa[fa[x][i-1]][i-1];
        adp[x][i]=max(adp[x][i-1],adp[fa[x][i-1]][i-1]);
        if (adp[x][i-1]==adp[fa[x][i-1]][i-1])
        {
            bdp[x][i]=max(bdp[x][i-1],bdp[fa[x][i-1]][i-1]);
        }
        else
        {
            bdp[x][i]=min(adp[x][i-1],adp[fa[x][i-1]][i-1]);
            bdp[x][i]=max(bdp[x][i],bdp[x][i-1]);
            bdp[x][i]=max(bdp[x][i],bdp[fa[x][i-1]][i-1]);
        }
    }
    for (int i=head[x];i;i=e[i].next)
    {
        if (e[i].to!=ft)
        {
            fa[e[i].to][0]=x;
            adp[e[i].to][0]=e[i].v;
            deep[e[i].to]=deep[x]+1;
            dfs(e[i].to,x);
        }
    }
}
int dep;
int LCA(int x,int y)
{
    if (deep[x]<deep[y])
    {
        swap(x,y);
    }
    dep=deep[x]-deep[y];
    for (int i=0;i<=16;i++)
    {
        if ((1<<i)&dep)
        {
            x=fa[x][i];
        }
    }
    for (int i=16;i>=0;i--)
    {
        if (fa[x][i]!=fa[y][i])
        {
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    if (x==y) return x;
    return fa[x][0];
}

void lca(int x,int ft,int c)
{
    int maxa,maxb;
    maxa=maxb=0;
    dep=deep[x]-deep[ft];
    for (int i=0;i<=16;i++)
    {
        if (dep&(1<<i))
        {
            if (adp[x][i]>maxa)
            {
                maxb=maxa;
                maxa=adp[x][i];
            }
            maxb=max(maxb,bdp[x][i]);
            x=fa[x][i];
        }
    }
    if (maxa!=c)
    {
        amn=min(amn,c-maxa);
    }
    else
    {
        amn=min(amn,c-maxb);
    }
}
int x,y,ftr;
void func(int ww,int uu)
{
    x=a[ww].x;
    y=a[ww].y;
    ftr=LCA(x,y);
    lca(x,ftr,uu);
    lca(y,ftr,uu);
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        f[i]=i;
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val);
    }
    sort(a+1,a+m+1,cmp);
    for (int i=1,xx,yy;i<=m;i++)
    {
        xx=find(a[i].x); yy=find(a[i].y);
        if (xx!=yy)
        {
            f[xx]=yy;
            ans+=a[i].val;
            a[i].book=true;
            add(a[i].x,a[i].y,a[i].val);
            add(a[i].y,a[i].x,a[i].val);
            tot++;
            if (tot==n-1)
            {
                break;
            }
        }
    }
    dfs(1,0);
    for (int i=1;i<=m;i++)
    {
        if (!a[i].book)
        {
            func(i,a[i].val);
        }
    }
    printf("%lld",ans+amn);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Kan-kiz/p/10720259.html