bzoj1977
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
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
Sample Output
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的更多相关文章
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- bzoj1977 [BeiJing2010组队]次小生成树 Tree
和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)
非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...
- [BZOJ1977]严格次小生成树
[问题描述] 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等. 正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成 ...
- bzoj1977次小生成树(重要)
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #inclu ...
- [BZOJ1977][BeiJing2010组队]次小生成树
题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...
- BZOJ1977或洛谷4180 [BJWC2010]次小生成树
一道LCA+生成树 BZOJ原题链接 洛谷原题链接 细节挺多,我调了半天..累炸.. 回到正题,我们先求出随便一棵最小生成树(设边权和为\(s\)),然后扫描剩下所有边,设扫到的边的两端点为\(x,y ...
- 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)
传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...
随机推荐
- uitextfield银行卡加空格
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementS ...
- bison实例
逆波兰记号计算器[文件名rpcalc.y]%{ #define YYSTYPE double #include <stdio.h> #include <math.h> #inc ...
- JavaScript中时间戳和时间的相互转换
时间转换成时间戳: var time = new Date(); var timestamp=Date.parse(time) //毫秒数,得到秒除以1000: 时间戳转成时间: 1.转换成 20 ...
- 转 错误:ORA-28002: the password will expire within 7 days 解决方法
今天在使用sqlplus时出现 =============================================== ERROR:ORA-28002: the password will e ...
- win10十周年更新后cent os 虚拟机无法连接到xshell
1.在vmware中打开编辑-->虚拟网络编辑器-->还原默认设置
- eclipse怎么连接到MySQL中的表!!!!!
简介: 用eclipse编写的好的代码,我们怎么才能连接到数据库呢?对于初学者,特别是在连接数据库这块经常会发生一些莫名的错误,一般来说,归根是我们连接数据库这一过程发生错误.那么我们如何来解决呢?那 ...
- MPI编程简介[转]
原文地址http://blog.csdn.net/qinggebuyao/article/details/8059300 3.1 MPI简介 多线程是一种便捷的模型,其中每个线程都可以访问其它线程的存 ...
- WEB前端组件思想【分页】
DEMO1: 很早就想写一些功能性的组件,无奈技术有限一点一点的边工作,边学. 近日工作中用到分页功能,当然由于加快业务进度,第一选择肯定是选择插件,但是实用性来说,还是有那么一点不适合.毕竟插件是通 ...
- Java 集合 散列表hash table
Java 集合 散列表hash table @author ixenos 摘要:hash table用链表数组实现.解决散列表的冲突:开放地址法 和 链地址法(冲突链表方式) hash table 是 ...
- More on wrapper types
原文地址:http://fsharpforfunandprofit.com/posts/computation-expressions-wrapper-types-part2/ 上一篇中,我们说明了包 ...