码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-09-24 17:17:53      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:The   space   style   tar   mat   vector   include   并且   ring   

传送门

次小生成树

那肯定是最小生成树上改一条边(改两条肯定不如只改其中一条小)

那就枚举所有不在最小生成树上的边

考虑如果把此边加入,另一边删除后的情况

考虑要删哪条边后才能保持树的形态,并且总长最小

加入一条边后树就会出现一个环

那么删掉的边要在加入的边连接的两点间的路径上

并且删去的边要尽量大

那就可以用LCA来求出树上两点间路径上的最长边

但是现在还有一个问题,可能删去的边和加入的边一样长

所以还要维护一下次长的边

次长边维护也不难,具体看代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
inline int read()
{
    int x=0; char ch=getchar();
    while(ch<0||ch>9) ch=getchar();
    while(ch>=0&&ch<=9)
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x;
}

const int N=1e5+7;
const int M=3e5+7;
int n,m;
int fa[N];
long long s;
inline int find(int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); }
struct edge
{
    int a,b,c;
}e[M];
inline bool cmp(const edge &a,const edge &b){ return a.c<b.c; }

vector <int> v[N],g[N];
bool p[M];
int f[N][27],dep[N];
long long mx[N][27],mxx[N][27];//mxx存次长边
void dfs(int x,int father)
{
    dep[x]=dep[father]+1; f[x][0]=father;
    for(int i=1;i<=20;i++)
    {
        f[x][i]=f[f[x][i-1]][i-1];
        mx[x][i]=max(mx[f[x][i-1]][i-1],mx[x][i-1]);
        mxx[x][i]=max(mxx[f[x][i-1]][i-1],mxx[x][i-1]);

        if(mx[ f[x][i-1] ][i-1]>mx[x][i-1])
            mxx[x][i]=max(mxx[x][i],mx[x][i-1]);
        if(mx[x][i-1]>mx[ f[x][i-1] ][i-1])
            mxx[x][i]=max(mxx[x][i],mx[ f[x][i-1] ][i-1]);
    }
    int len=v[x].size();
    for(int i=0;i<len;i++)
    {
        int u=v[x][i];
        if(u==father) continue;
        mx[u][0]=g[x][i]; mxx[u][0]=-1;
        dfs(u,x);
    }
}
inline long long LCA(int x,int y,int z)//询问最长边或者次长边
{
    long long res=-1e17+7;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
        {
            if(mx[x][i]!=z) res=max(res,mx[x][i]);
            else res=max(res,mxx[x][i]);
            x=f[x][i];
        }
    if(x==y) return res;
    for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            if(mx[x][i]!=z) res=max(res,mx[x][i]);
            else res=max(res,mxx[x][i]);
            if(mx[y][i]!=z) res=max(res,mx[y][i]);
            else res=max(res,mxx[y][i]);
            x=f[x][i]; y=f[y][i];
        }
    if(mx[x][0]!=z) res=max(res,mx[x][0]);
    else res=max(res,mxx[x][0]);
    if(mx[y][0]!=z) res=max(res,mx[y][0]);
    else res=max(res,mxx[y][0]);
    return res;
}

int main()
{
    n=read(); m=read();
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
        e[i].a=read(),e[i].b=read(),e[i].c=read();

    sort(e+1,e+m+1,cmp);
    int tot=0;
    for(int i=1;i<=m;i++)
    {
        int xa=find(e[i].a),xb=find(e[i].b);
        if(xa==xb) continue;
        s+=e[i].c; fa[xa]=xb;  p[i]=1;
        v[e[i].a].push_back(e[i].b); g[e[i].a].push_back(e[i].c);
        v[e[i].b].push_back(e[i].a); g[e[i].b].push_back(e[i].c);
        if(++tot==n-1) break;
    }//先求出最小生成树

    dfs(1,1);
    long long ans=1e17+7;
    for(int i=1;i<=m;i++)
    {
        if(p[i]) continue;//枚举所有没有加入最小生成树的边
        long long t=LCA(e[i].a,e[i].b,e[i].c);//找出最长边或者次长边
        if(t==e[i].c) continue;
        ans=min(ans,s-t+e[i].c);
    }
    cout<<ans;
    return 0;
}

 

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

标签:The   space   style   tar   mat   vector   include   并且   ring   

原文地址:https://www.cnblogs.com/LLTYYC/p/9695527.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!