[模板] 严格次小生成树

题目链接

先求当前图中的最小生成树,再将没有选的边一一安放(放完一个就卸下),这样每次就形成一个环,再求这个环除了它以外的最短权值,这样就会想到lca,因为树的路径是唯一的,并且时间也不会超时,再将原答案加上这条边的权值减去最大的环上权值的最小值即为答案

调了一下午,哎~,板子打WA了,一个1<<i被我写成了i<<1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
long long n,m,f[1200001];
struct node1{
    long long u,v,w;
}x[1200001];
bool cmp(node1 x1,node1 x2)
{
    return x1.w<x2.w;
 } 
long long find(long long x)
{
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
struct node{
    long long u,v,w;
}xx[1200001];
struct node3{
    long long u,v,w,nex;
}s[1200001];
long long cntt;
long long cnt;
long long ans;
long long head[1200001];
long long maxn1[1200001][21],maxn2[1200001][21],fa[1200001][21],deep[1200001];
long long data=0x3f3f3f3f3f3f3f3f;
void add(long long u,long long v,long long w)
{
    s[cntt].u=u,s[cntt].v=v,s[cntt].w=w,s[cntt].nex=head[u],head[u]=cntt++;
}
void dfs(long long f,long long fath)
{
    deep[f]=deep[fath]+1;
    fa[f][0]=fath;
    for(long long i=1;(1<<i)<=deep[f];i++)
    {
        fa[f][i]=fa[fa[f][i-1]][i-1];
        maxn1[f][i]=max(maxn1[f][i-1],maxn1[fa[f][i-1]][i-1]);
        if(maxn1[f][i-1]==maxn1[fa[f][i-1]][i-1]) maxn2[f][i]=max(maxn2[f][i-1],maxn2[fa[f][i-1]][i-1]);
        else maxn2[f][i]=max(min(maxn1[f][i-1],maxn1[fa[f][i-1]][i-1]),max(maxn2[f][i-1],maxn2[fa[f][i-1]][i-1]));
    }
    for(long long i=head[f];i!=-1;i=s[i].nex)
    {
        if(s[i].v==fath) continue;
        maxn1[s[i].v][0]=s[i].w;
        dfs(s[i].v,f); 
    }
}
void kcal()
{
    memset(head,-1,sizeof(head));
    n=read(),m=read();
    for(long long i=1;i<=n;i++) f[i]=i;
    for(long long i=1;i<=m;i++) x[i].u=read(),x[i].v=read(),x[i].w=read(); 
    sort(x+1,x+m+1,cmp);
    for(long long i=1;i<=m;i++)
    {
        long long t1=find(x[i].u),t2=find(x[i].v);
        if(t1!=t2)
        {
            f[t2]=t1;
            ans+=x[i].w;
            add(x[i].u,x[i].v,x[i].w),add(x[i].v,x[i].u,x[i].w);
        }
        else xx[++cnt].u=x[i].u,xx[cnt].v=x[i].v,xx[cnt].w=x[i].w;
    }
}
long long lca(long long u,long long v,long long w)
{
    long long dis1=-1,dis2=-1;
    if(deep[u]<deep[v]) swap(u,v);
    for(long long i=17;i>=0;i--)
    {
        if(deep[u]-(1<<i)>=deep[v]) 
        {    
            dis2=max(dis2,maxn2[u][i]);
            if(maxn1[u][i]>dis1) dis2=max(dis1,max(dis2,maxn2[u][i])),dis1=maxn1[u][i];
            else dis2=max(dis2,maxn1[u][i]);
            u=fa[u][i];
        }
    }
    if(u==v) 
    {
        if(dis1!=w) return dis1;
        if(dis2!=w) return dis2;
        else return -(2<<30-1);
    }
    for(long long i=17;i>=0;i--)
    {
        
        if(fa[u][i]==fa[v][i]) continue;
        dis2=max(dis2,maxn2[u][i]);
        if(maxn1[u][i]>dis1) dis2=max(dis1,max(dis2,maxn2[u][i])),dis1=maxn1[u][i];
        else dis2=max(dis2,maxn1[u][i]);
        u=fa[u][i];
        dis2=max(dis2,maxn2[v][i]);
        if(maxn1[v][i]>dis1) dis2=max(dis1,max(dis2,maxn2[v][i])),dis1=maxn1[v][i];
        else dis2=max(dis2,maxn1[v][i]);
        v=fa[v][i];
    }
    dis2=max(dis2,maxn2[u][0]);
    if(maxn1[u][0]>dis1) dis2=max(dis1,max(dis2,maxn2[u][0])),dis1=maxn1[u][0];
    else dis2=max(dis2,maxn1[u][0]);
    u=fa[u][0];
    dis2=max(dis2,maxn2[v][0]);
    if(maxn1[v][0]>dis1) dis2=max(dis1,max(dis2,maxn2[v][0])),dis1=maxn1[v][0];
    else dis2=max(dis2,maxn1[v][0]);
    v=fa[v][0];
    if(dis1!=w) return dis1;
    if(dis2!=w) return dis2;
    else return -(2<<30-1);
}
int main()
{
    kcal();
    dfs(1,0);
    for(long long i=1;i<=cnt;i++)  data=min(data,ans+xx[i].w-lca(xx[i].u,xx[i].v,xx[i].w));
    cout<<data;
}

分享一组被hack的数据

input: 5 6 1 2 3 1 3 3 2 3 3 3 4 3 3 5 3 4 5 8

the answer: 17 

原文地址:https://www.cnblogs.com/si-rui-yang/p/9535192.html