bzoj1977次小生成树(重要)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define Maxn 300010
#define maxn 300005
using namespace std;
#define ll long long
struct edge{
int to,w,nxt;
}edge[Maxn];
int head[Maxn/],tot;
void addedge(int a,int b,int c){
edge[tot].to=b;
edge[tot].w=c;
edge[tot].nxt=head[a];
head[a]=tot++;
}
struct line{
int u,v,w;
bool operator<(const line &a)const{
return w<a.w;
}
}q[Maxn]; int vis[Maxn];
int fa[Maxn/];
int findset(int x){
return fa[x]==x?x:(fa[x]=findset(fa[x]));
}
int unionset(int a,int b){
return fa[findset(a)]=findset(b);
}
ll d[maxn],f[maxn][],dp[maxn][][];//dp[i][j][0|1]用来表示向上倍增的最大边,严格次大边
void bfs(){
queue<int>q;
q.push();
d[]=;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to;
if(d[y])continue;
d[y]=d[x]+;
f[y][]=x;
dp[y][][]=edge[i].w;
dp[y][][]=-0x3f3f3f3f;
for(int k=;k<=;k++){
f[y][k]=f[f[y][k-]][k-];
int a=dp[y][k-][];//y向上下一半的最大值
int b=dp[y][k-][];//y向上下一半的严格次大值
int c=dp[f[y][k-]][k-][];//y向上上一半的最大值
int d=dp[f[y][k-]][k-][];//y向上上一半的严格次大值
dp[y][k][]=max(a,c);
if(a==c)dp[x][k][]=max(b,d);
else if(a>c)dp[x][k][]=max(c,b);
else if(a<c)dp[x][k][]=max(a,d);
}
q.push(y);
}
}
}
inline void calc(ll &val1,ll &val2,ll a,ll b){//更新最大和次大
if(a<=val1)val2=max(a,val2);
else val2=val1,val1=a;
}
int lca(int x,int y,int z){//处理加入(x,y,z)后的次小生成树
ll val1=-,val2=-;
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;i--)
if(d[f[x][i]]>=d[y]){
calc(val1,val2,dp[x][i][],dp[x][i][]);
x=f[x][i];
}
if(x==y){
if(val1!=z)return val1;
return val2;
} for(int i=;i>=;i--)
if(f[x][i]!=f[y][i]){
calc(val1,val2,dp[x][i][],dp[x][i][]);
calc(val1,val2,dp[y][i][],dp[y][i][]);
x=f[x][i],y=f[y][i];
}
calc(val1,val2,dp[x][][],dp[x][][]);
calc(val1,val2,dp[y][][],dp[y][][]);
x=f[x][];
if(val1!=z)return val1;
else return val2;
} int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<m;i++)
scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w);
sort(q,q+m);
for(int i=;i<=n;i++) fa[i]=i;
memset(head,-,sizeof head);
memset(vis,,sizeof vis);
tot=;
int cnt=;
long long ans=;
for(int i=;i<m;i++){
int u=q[i].u,v=q[i].v;
if(findset(u)==findset(v)) continue;
unionset(u,v);
vis[i]=;
addedge(u,v,q[i].w);
addedge(v,u,q[i].w);
ans+=q[i].w;
if(++cnt==n-) break;
}
bfs();
int z=0x3f3f3f3f;
for(int i=;i<m;i++)
if(!vis[i]) {
int t=lca(q[i].u,q[i].v,q[i].w);
if(t>)z=min(z,-t+q[i].w);
}
printf("%lld\n",ans+z);
return ;
}
bzoj1977次小生成树(重要)的更多相关文章
- 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)
传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...
- bzoj1977 次小生成树
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- 【次小生成树】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][BeiJing2010组队]次小生成树
题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...
随机推荐
- Mybatis(一)入门介绍
一.MyBatis的发展 MyBatis 是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到google code, 并且改名M ...
- B - Tree Rotations HYSBZ - 2212 (线段树合并)
题目链接:https://cn.vjudge.net/contest/287725#problem/B 题目大意:现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有n个叶子节 ...
- CNN学习入门
https://blog.csdn.net/ice_actor/article/details/78648780
- scrapy基础 之 静态网页实例
1,scrapy爬虫基本流程: 1. 创建一个新的Scrapy Project > scrapy startproject 项目名称 #系统会在当前目录下创建一个项目名称命名的文件夹,其下 ...
- 获取异步API数据
异步操作应该是以前学习 ajax 时才被明确提及,就目前的理解,同步就是同一时间只能做一件事,如果使用 ajax同步模式,则代码会卡在 xhr.send() 这里,只有请求响应的过程全部完成了才会执行 ...
- Bringing Native Performance to Electron
Bringing Native Performance to Electron https://realm.io/blog/native-performance-electron-realm/ Rea ...
- HTTP笔记01-http相关的基础知识
这个系列文章是阅读<图解HTTP>后写下的笔记 当我们在浏览器输入url,点击回车后,浏览器显示我们需要的web页面,那么,这个界面是如何产生的? 根据浏览器地址中输入的url,浏览器从相 ...
- C#代码处理前台html标签拼接
之前一篇文章是写,JavaScript处理特殊字符拼接时截断问题.最近在处理公司老软件兼容性升级时碰到的一个类似的问题,这次是后台拼接字符串,前台.aspx页面显示的.中间走了两次弯路,在此记录一下. ...
- boost.lexical_cast 学习
1,字符串 到 数值类型的转换 2,数值 到 字符串的转换 3,异常处理情况 4,boost::lexical_cast 的原型: template<typename Target, typen ...
- 【转】采用dlopen、dlsym、dlclose加载动态链接库
1.前言 为了使程序方便扩展,具备通用性,可以采用插件形式.采用异步事件驱动模型,保证主控制逻辑不变,将各个业务以动态链接库的形式加载进来,这就是所谓的插件.linux提供了加载和处理动态链接库的系统 ...