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*];
struct edge1
{
int u,v,w;
};
vector<edge1> E;
int n,m,cnt=;
ll tot;
int head[N],father[N],dep[N],mark[N];
int fa[N][];
ll maxcost[N][];
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]+;
fa[v][]=u;
maxcost[v][]=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=;i>=;i--) if((dep[u]-dep[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]);
u=fa[u][i];
}
if(u==v) return ret;
for(int i=;i>=;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][]>ret.first)
{
ret.second=ret.first;
ret.first=maxcost[u][];
}
else if(maxcost[u][]<ret.first)
ret.second=max(ret.second,maxcost[u][]);
if(maxcost[v][]>ret.first)
{
ret.second=ret.first;
ret.first=maxcost[v][];
}
else if(maxcost[v][]<ret.first)
ret.second=max(ret.second,maxcost[v][]);
return ret;
}
void build()
{
for(int i=;i<=;i++)
for(int j=;j<=n;j++) if(fa[j][i-]!=-)
{
fa[j][i]=fa[fa[j][i-]][i-];
maxcost[j][i]=max(maxcost[j][i-],
maxcost[fa[j][i-]][i-]);
}
}
void kruskal()
{
sort(E.begin(),E.end(),cp);
for(int i=;i<=n;i++) father[i]=i;
for(int i=;i<E.size();i++) if(find(E[i].u)!=find(E[i].v))
{
connect(E[i].u,E[i].v);
mark[i]=;
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(,);
build();
ll ans=(ll)(1e17);
for(int i=;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=;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 ;
}

bzoj1977的更多相关文章

  1. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

  2. bzoj1977 [BeiJing2010组队]次小生成树 Tree

    和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...

  3. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  4. 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)

    非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...

  5. [BZOJ1977]严格次小生成树

    [问题描述] 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等. 正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成 ...

  6. bzoj1977次小生成树(重要)

    #include<cstdio> #include<iostream> #include<cstring> #include<queue> #inclu ...

  7. [BZOJ1977][BeiJing2010组队]次小生成树

    题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...

  8. BZOJ1977或洛谷4180 [BJWC2010]次小生成树

    一道LCA+生成树 BZOJ原题链接 洛谷原题链接 细节挺多,我调了半天..累炸.. 回到正题,我们先求出随便一棵最小生成树(设边权和为\(s\)),然后扫描剩下所有边,设扫到的边的两端点为\(x,y ...

  9. 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)

    传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...

随机推荐

  1. CentOS6.5 安装mysql5.6.30

    1.下载解压由于系统会自带mysql5.1版本的数据库,需要卸载.[root@localhost src]# yum remove -y mysql-libs[root@localhost src]# ...

  2. select空间提交form表单传递参数

    如下, 到了 <form name="modelForm" action="/portal/defectinfo/toDefectPage?projectname= ...

  3. 关于C语言知识调查

    因为上一篇随笔对这一部分写得不够清楚,因此在这篇做一些补充. 你是怎么学习C语言的? 起初,对于C语言的学习主要是通过老师课堂的教学,完成相关的课后作业.与我的技能相比的话,他们都有一个共同点需要去实 ...

  4. C# 手机格式验证

    C# 手机格式验证 //电信手机号码正则 Regex dReg = new Regex(@"^1[3578][01379]\d{8}$"); //联通手机号正则 Regex tRe ...

  5. 使用vs2010打开VS2013的工程文件

    在开发团队,会出现vs工具使用版本的不一样的情况.我的电脑使用的是VS2010,可是其他人员使用的是vs2013. 要打开其他人员上传的工程文件,可以通过三种方式: 1.下载一个vs2013版本. 2 ...

  6. QT源码剖析之QSS样式表

    1. "QApplication::setStyleSheet()"设置样式表: 1. 创建新的样式表. 2. 设置新的样式. void QApplication::setStyl ...

  7. php curl 抓取内容

    <?php$ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url)//抓取url curl_setopt($ch,CURLOPT_RETURNTRAN ...

  8. Base64编码 图片与base64编码互转

    package com.education.util; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import jav ...

  9. IOC(控制反转)

    一.容器与Bean 在Spring中,那些组成你应用程序的主体(backbone)及由Spring IoC容器所管理的对象,被称之为bean. 简单地讲,bean就是由Spring容器初始化.装配及管 ...

  10. java-成员方法/变量、类方法/变量等区别

    方法 成员方法 成员方法也叫实例方法.必须先有实例即对象,然后才能通过实例调用该实例方法. 类方法 和类变量一样,有关键字static修饰,可以不用实例,直接用类就可以调用类方法. 变量 成员变量 也 ...