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

bzoj1977

时间:2017-01-15 00:15:56      阅读:253      评论:0      收藏:0      [点我收藏+]

标签:nbsp   beijing   put   bool   倍增   code   答案   gre   lld   

1977: [BeiJing2010组队]次小生成树 Tree

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 3001  Solved: 751
[Submit][Status][Discuss]

Description

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 技术分享 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

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

Output

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

Sample Input

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

Sample Output

11

HINT

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

Source

首先我们要知道次小生成树是最小生成树删掉一条边并加上一条边,那么枚举每条边,通过倍增计算最小边和次小边,计算答案即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
#define N 100010
struct edge
{
    int to,nxt,w;
}e[N*6];
struct edge1 
{
    int u,v,w;
};
vector<edge1> E;
int n,m,cnt=1;
ll tot;
int head[N],father[N],dep[N],mark[N];
int fa[N][23];
ll maxcost[N][23];
ll max(ll x,ll y)
{
    return x>y?x:y;
}
ll min(ll x,ll y)
{
    return x<y?x:y;
}
bool cp(edge1 x,edge1 y)
{
    return x.w<y.w;
}
void link(int u,int v,int w)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;
    e[cnt].w=w;
}
int find(int u)
{
    return u==father[u]?father[u]:find(father[u]);
}
void connect(int u,int v)
{
    int a=find(u);
    int b=find(v);
    if(a==b) return;
    father[a]=b;
}
void dfs(int u,int Fa)
{
    for(int i=head[u];i;i=e[i].nxt) if(e[i].to!=Fa)
    {
        int v=e[i].to;
        dep[v]=dep[u]+1;
        fa[v][0]=u;
        maxcost[v][0]=e[i].w;
        dfs(v,u);
    }
}
PII lca(int u,int v)
{
    PII ret;
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=22;i>=0;i--) if((dep[u]-dep[v])&(1<<i)) 
    {
        if(maxcost[u][i]>ret.first)
        {
            ret.second=ret.first;
            ret.first=maxcost[u][i];
        }
        else if(maxcost[u][i]<ret.first)
            ret.second=max(ret.second,maxcost[u][i]);
        u=fa[u][i];
    }
    if(u==v) return ret;
    for(int i=22;i>=0;i--) if(fa[u][i]!=fa[v][i]) 
    {
        if(maxcost[u][i]>ret.first)
        {
            ret.second=ret.first;
            ret.first=maxcost[u][i];
        }
        else if(maxcost[u][i]<ret.first)
            ret.second=max(ret.second,maxcost[u][i]);
        if(maxcost[v][i]>ret.first)
        {
            ret.second=ret.first;
            ret.first=maxcost[v][i];
        }
        else if(maxcost[v][i]<ret.first)
            ret.second=max(ret.second,maxcost[v][i]);
        u=fa[u][i]; v=fa[v][i];
    }
    if(maxcost[u][0]>ret.first)
    {
        ret.second=ret.first;
        ret.first=maxcost[u][0];
    }
    else if(maxcost[u][0]<ret.first)
        ret.second=max(ret.second,maxcost[u][0]);
    if(maxcost[v][0]>ret.first)
    {
        ret.second=ret.first;
        ret.first=maxcost[v][0];
    }
    else if(maxcost[v][0]<ret.first)
        ret.second=max(ret.second,maxcost[v][0]);
    return ret;
}
void build()
{
    for(int i=1;i<=22;i++)
        for(int j=1;j<=n;j++) if(fa[j][i-1]!=-1)
        {
            fa[j][i]=fa[fa[j][i-1]][i-1];
            maxcost[j][i]=max(maxcost[j][i-1],
            maxcost[fa[j][i-1]][i-1]);
        }
}
void kruskal()
{
    sort(E.begin(),E.end(),cp);
    for(int i=1;i<=n;i++) father[i]=i;
    for(int i=0;i<E.size();i++) if(find(E[i].u)!=find(E[i].v))
    {
        connect(E[i].u,E[i].v);
        mark[i]=1;
        tot+=E[i].w;
        link(E[i].u,E[i].v,E[i].w);
        link(E[i].v,E[i].u,E[i].w);
    }
    dfs(1,1);
    build();
    ll ans=(ll)(1e17);
    for(int i=0;i<E.size();i++) if(!mark[i])
    {
        PII x=lca(E[i].u,E[i].v);
        if(x.first<E[i].w) ans=min(ans,tot+E[i].w-x.first);
        else if(x.first==E[i].w) ans=min(ans,tot+E[i].w-x.second);
    }
    printf("%lld",ans);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,w; scanf("%d%d%d",&u,&v,&w);
        edge1 x;
        x.u=u; x.v=v; x.w=w;
        E.push_back(x);
    }
    kruskal();
    return 0;
}

 

bzoj1977

标签:nbsp   beijing   put   bool   倍增   code   答案   gre   lld   

原文地址:http://www.cnblogs.com/19992147orz/p/6286355.html

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