严格次小生成树 最小生成树+树上倍增

严格次小生成树

一定要注意是严格次小!!。。。

Solution:

相信大家不难想到:

先做一遍最小生成树,然后枚举剩下的边,然后在树上倍增,把最大的那条边给去掉,把这条给加上,全局取min。

然后你会发现你开心的交完后,只有80。

I:诶诶诶,怎么回事,明明是没错的啊。再看看。。。

某神ben:你好呆( ̄_, ̄ )看了题目没。。。

I:略略略,溜了溜了。。

好吧,这个题唯一需要注意的就是:严格次小!严格次小!严格次小!

这意味着:

不仅需要维护最大值的倍增数组,还需要维护次大值的倍增数组。

Code↓:

#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

IL int gi() {
    char ch=getchar(); RG int x=0,w=0;
    while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
    return w?-x:x;
}

const int N=1e5+10;
const int M=3e5+10;

LL sum,Ans=1e18;
int n,m,tot,head[N],fa[N],tag[M],dep[N],f[N][21],g[N][21],t[N][21];

struct Edge{int x,y,z;}e[M];
struct EDGE{int next,to,v;}E[N<<1];

IL bool cmp(Edge A,Edge B) {return A.z<B.z;}

IL void make(int a,int b,int c) {
    E[++tot]=(EDGE){head[a],b,c},head[a]=tot;
    E[++tot]=(EDGE){head[b],a,c},head[b]=tot;
}

IL int getfa(int x) {return x==fa[x]?x:fa[x]=getfa(fa[x]);}

IL void Kruskal() {
    RG int i,x,y,fx,fy,num=0;
    sort(e+1,e+m+1,cmp);
    for (i=1;i<=n;++i) fa[i]=i;
    for (i=1;i<=m;++i) {
        x=e[i].x,y=e[i].y,fx=getfa(x),fy=getfa(y);
        if (fx!=fy) {
            tag[i]=1,fa[fx]=fy,sum+=e[i].z,make(x,y,e[i].z);
            if (++num==n-1) break; 
        }
    }
}

void dfs(int x,int fx) {
    RG int i,y;
    for (i=head[x],dep[x]=dep[fx]+1;i;i=E[i].next)
        if ((y=E[i].to)!=fx) f[y][0]=x,g[y][0]=E[i].v,dfs(y,x);
}

IL void work() {
    RG int i,j,p;
    for (i=1;i<=20;++i)
        for (j=1;j<=n;++j) {
            p=f[j][i-1],f[j][i]=f[p][i-1];
            if (g[j][i-1]>g[p][i-1]) g[j][i]=g[j][i-1],t[j][i]=max(g[p][i-1],t[j][i-1]);
            if (g[j][i-1]<g[p][i-1]) g[j][i]=g[p][i-1],t[j][i]=max(g[j][i-1],t[p][i-1]);
            if (g[j][i-1]==g[p][i-1]) g[j][i]=g[p][i-1],t[j][i]=max(t[j][i-1],t[p][i-1]);
        }
}

IL int getMax(int x,int y,int ver) {
    RG int i,ans=0;
    if (dep[x]<dep[y]) swap(x,y);
    for (i=20;i>=0;--i)
        if (dep[f[x][i]]>=dep[y]) {
            if (g[x][i]<ver) ans=max(ans,g[x][i]);
            x=f[x][i];
        } 
    if (x==y) return ans;
    for (i=20;i>=0;--i)
        if (f[x][i]!=f[y][i]) {
            if (g[x][i]<ver) ans=max(ans,g[x][i]);
            if (g[y][i]<ver) ans=max(ans,g[y][i]);
            x=f[x][i],y=f[y][i];
        }
    if (g[x][0]<ver) ans=max(ans,g[x][0]);
    if (g[y][0]<ver) ans=max(ans,g[y][0]);
    return ans;
}

int main()
{
    RG int i,now;
    n=gi(),m=gi();
    for (i=1;i<=m;++i) e[i].x=gi(),e[i].y=gi(),e[i].z=gi();
    Kruskal(),dfs(1,0),work();
    for (i=1;i<=m;++i)
        if (!tag[i]) {
            now=getMax(e[i].x,e[i].y,e[i].z);
            Ans=min(Ans,sum+e[i].z-now);
        }
    printf("%lld\n",Ans);
    return 0;
}

// 严格次小 不能相等啊...

The End

猜你喜欢

转载自www.cnblogs.com/Bhllx/p/10617109.html
今日推荐