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. javaMail邮件发送的简单实现

    package com.test.mail; import java.util.Properties; import javax.mail.Message; import javax.mail.Ses ...

  2. iframe标签使用总结与注意问题

    子页面访问父父页面变量,函数,页面元素 //变量: //在父页面中需定义为全局变量 //子页面中调用 var childFrameVar= parent.ParentVarName; //函数: pa ...

  3. 训练[2]-DFS

    题目A: 题目B[https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_pro ...

  4. webStorm(一)

    1.打开webStorm选择activation code输入注册码 43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIj ...

  5. android从assets读取文件的方法

    因为开发需要,经常要从工程的assets文件夹里面读取文件,现在贴一个方法以作记录: private void getFromAssets(String fileName, ArrayList< ...

  6. selenium grid的使用与配置

    一.selenium grid的组成与作用:由一个集线器hub和多个客户机node组成,如果你的程序需要在不用的浏览器,不同的操作系统上测试,而且比较多的case需要多线程远程执行,那么一个比较好的测 ...

  7. 不容忽略的——CSS规范

    一.CSS分类方法: 公共型样式 特殊型样式 皮肤型样式 并以此顺序引用 <link href="assets/css/global.css" rel="style ...

  8. 模拟点击a链接

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head&g ...

  9. html5--画布

    简介 canvas是HTML5中的新元素,你可以使用javascript用它来绘制图形.图标.以及其它任何视觉性图像.它也可用于创建图片特效和动画.canvas 元素本身是没有绘图能力的.所有的绘制工 ...

  10. 更改自身web项目的图标(默认为tomcat的小喵咪)

    在页面<head>标签中加入 <link rel="shortcut icon" href="img/11.png" type="i ...