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

题目描述

小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)eEMvalue(e)<eESvalue(e)

这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

输入输出格式

输入格式:

 

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

 

输出格式:

 

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

 

输入输出样例

输入样例#1: 复制
5 6
1 2 1 
1 3 2 
2 4 3 
3 5 4 
3 4 3 
4 5 6 
输出样例#1: 复制
11

说明

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

 

又只有90。。。脸黑RE没办法     是我太菜

蓝书上关于生成树的地方讲得还是很清楚的!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<complex>
#define N 400010
#define M 900010
#define INF 214748364700000
#define ll long long
using namespace std;
ll read()
{
    ll x=0,f=1;char s=getchar();
    while(s>'9' || s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9' && s>='0'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
struct edge{ll to,next,v;}a[N<<1];
struct node{ll x,y,v;}e[M];
bool operator < (node a,node b){return a.v<b.v;}
ll cnt,head[N],t=0;
void add(ll x,ll y,ll v){a[++cnt].to=y;a[cnt].v=v;a[cnt].next=head[x];head[x]=cnt;}
ll bz[N][21],deep[N],m1[N][21],m2[N][21],f[N],V[N];
ll find(ll x){if(x==f[x])return x;f[x]=find(f[x]);return f[x];}
int n,m;
void dfs(ll x,ll fa)
{
    bz[x][0]=fa;
    for(int i=head[x];i;i=a[i].next)
    {
        ll v=a[i].to;
        if(v==fa)continue;
        deep[v]=deep[x]+1;
        m1[v][0]=a[i].v;
        m2[v][0]=-INF;
        dfs(v,x);
    }
}
void twofold()
{
    for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++)
        {
            bz[j][i]=bz[bz[j][i-1]][i-1];
            m1[j][i]=max(m1[j][i-1],m1[bz[j][i-1]][i-1]);
            m2[j][i]=max(m2[j][i-1],m2[bz[j][i-1]][i-1]);
            if(m1[j][i-1]>m1[bz[j][i-1]][i-1])m2[j][i]=max(m2[j][i],m1[bz[j][i-1]][i-1]);
            else if(m1[j][i-1]<m1[bz[j][i-1]][i-1])m2[j][i]=max(m2[j][i],m1[j][i-1]);
        }
}
ll lca(ll x,ll y)
{
    if(deep[x]<deep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(deep[bz[x][i]]>=deep[y])x=bz[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;i--)
        if(bz[x][i]!=bz[y][i])x=bz[x][i],y=bz[y][i];
    return bz[x][0];
}
ll qmax(ll x,ll y,ll d)
{
    ll s=-INF;
    for(int i=20;i>=0;i--)
        if(deep[bz[x][i]]>=deep[y])
        {
            if(d!=m1[x][i])s=max(s,m1[x][i]);
            else s=max(s,m2[x][i]);
            x=bz[x][i];
        }
    return s;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].v=read();    sort(e+1,e+m+1);
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=m;i++)
    {
        ll p=find(e[i].x),q=find(e[i].y);
        if(p!=q)
        {
            t+=e[i].v;f[p]=q;V[i]=1;
            add(e[i].x,e[i].y,e[i].v);add(e[i].y,e[i].x,e[i].v);
        }
    }
    deep[1]=1;m2[1][0]=-INF;
    dfs(1,-1);twofold();
    ll ans=INF;
    for(int i=1;i<=m;i++)
        if(!V[i])
        {
            ll x=e[i].x,y=e[i].y,d=e[i].v,l=lca(x,y),p;
            p=t-max(qmax(x,l,d),qmax(y,l,d))+d;
            ans=min(ans,p);
        }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-04-04 16:46 hyf20010101 阅读(...) 评论(...) 编辑 收藏