#3775 次小生成树

题面
给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树。
设最小生成树的边权之和为sum,严格次小生成树就是指边权之和大于 sum 的生成树中最小的一个。

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

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

样例输入
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

样例输出
11

提示
对于全部数据,1≤N≤105,1≤M≤3×1051≤N≤105,1≤M≤3×105,1≤N≤10^5,1≤M≤3×10^51≤N≤10^5,1≤M≤3×10^5,1≤N≤105,1≤M≤3×1051≤N≤105,1≤M≤3×105,数据中无向图无自环,边权值非负且不超过 109​​10^9 ​​109​​ 。

SOL
对于一颗最小生成树,我们可以枚举树中的每条非树边并用这条边去尝试做出一些替换,但是光靠枚举效率很低,于是想到了LCA。
用LCA维护每条非树边两端点的LCA路径上的最大值和次大值(因为对于每一条非树边的两个端点,它的两个端点的树边上的边权最大值肯定小于等于这条非树边的权值,所以只需要考虑最大值和次大值)然后每次用非树边尝试替换,求出严格次小生成树。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 100005
#define M 300005
using namespace std;
inline int rd(){int register data=0,w=1;static char ch=0;while(!isdigit(ch)&&ch!='-')ch=getchar();if(ch=='-')w=-1,ch=getchar();while(isdigit(ch))data=(data<<1)+(data<<3)+ch-'0',ch=getchar();return data*w;
}
inline void write(int x){if(x>9)write(x/10);putchar(x%10+'0');}
int n,m,sum,minn=0x7f7f7f7f7f;
int fa[N],f[N][20],fir[N][20],sec[N][20],dep[N];
bool used[M];
inline int find(int x){return fa[x]==x? x:fa[x]=find(fa[x]);}
struct node{int u,v,w,nxt;}e[M<<1],E[M];
int cnt,first[N];
inline void add(int u,int v,int w){e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=first[u];first[u]=cnt;}
inline bool cmp(node a,node b){return a.w<b.w;}
inline void dfs(int u){for(int register i=1;(1<<i)<=dep[u];i++){f[u][i]=f[f[u][i-1]][i-1];fir[u][i]=max(fir[f[u][i-1]][i-1],fir[u][i-1]);if(fir[u][i-1]!=fir[f[u][i-1]][i-1])sec[u][i]=min(fir[u][i-1],fir[f[u][i-1]][i-1]);sec[u][i]=max(sec[u][i],max(sec[u][i-1],sec[f[u][i-1]][i-1]));}for(int register i=first[u];i;i=e[i].nxt){int register v=e[i].v;if(dep[v])continue;dep[v]=dep[u]+1;fir[v][0]=e[i].w;f[v][0]=u;dfs(v);}
}
typedef pair<int,int> T;
#define mp make_pair
inline T lca(int a,int b){if(dep[a]<dep[b])swap(a,b);int register gap=dep[a]-dep[b],firs=0,seco=0;for(int register i=0;(1<<i)<=gap;i++)if(gap&(1<<i)){if(firs!=fir[a][i])seco=max(seco,min(firs,fir[a][i]));seco=max(seco,sec[a][i]);firs=max(firs,fir[a][i]);a=f[a][i];}if(a==b)return mp(firs,seco);for(int register i=18;i>=0;i--){if(f[a][i]!=f[b][i]){if(firs!=fir[a][i])seco=max(seco,min(firs,fir[a][i]));seco=max(seco,sec[a][i]);firs=max(firs,fir[a][i]);if(firs!=fir[b][i])seco=max(seco,min(firs,fir[b][i]));seco=max(seco,sec[b][i]);firs=max(firs,fir[b][i]);a=f[a][i];b=f[b][i];         }}seco=max(seco,max(sec[b][0],sec[a][0]));if(firs!=fir[a][0])seco=max(seco,min(firs,fir[a][0]));if(firs!=fir[b][0])seco=max(seco,min(firs,fir[b][0]));firs=max(firs,max(fir[a][0],fir[b][0]));return mp(firs,seco);
}
signed main(){n=rd();m=rd();for(int register i=1;i<=n;i++)fa[i]=i;for(int register i=1;i<=m;i++){E[i].u=rd();E[i].v=rd();E[i].w=rd();}sort(E+1,E+m+1,cmp);for(int register i=1;i<=m;i++){int register u=E[i].u,v=E[i].v,w=E[i].w;int register fu=find(u),fv=find(v);if(fu!=fv){sum+=w;add(u,v,w);add(v,u,w);fa[fu]=fv;used[i]=1;}}dep[1]=1;dfs(1);for(int register i=1;i<=m;i++){if(used[i])continue;int register u=E[i].u,v=E[i].v,w=E[i].w;T tmp=lca(u,v);if(tmp.first!=w)minn=min(minn,w-tmp.first);else minn=min(minn,w-tmp.second);}write(sum+minn);return 0;
}

[FROM WOJ]#3775 次小生成树相关推荐

  1. poj 1679 次小生成树

    次小生成树的求法: 1.Prime法 定义一个二维数组F[i][j]表示点i到点j在最小生成树中的路径上的最大权值.有个知识就是将一条不在最小生成树中的边Edge加入最小生成树时,树中要去掉的边就是E ...

  2. HDU4081(次小生成树)

    1.其中:枚举每条不在最小生成树上的边,并把这条边放到最小生成树上面,然后就一定形成环,那么我们将这条环中取出最长的一条路.最终我们得到的权值便是最小生成树的权值. Max[i][j]表示的最小生成树 ...

  3. 模板 - LCA最近公共祖先(倍增法、Tarjan、树上差分、LCA优化的次小生成树)

    整理的算法模板合集: ACM模板 注意x和y的LCA可以是x或者y本身 一.LCA的在线倍增算法 /*给定一棵包含 n个节点的有根无向树,有 m个询问,每个询问 给出了一对节点的编号 x和 y,询问 ...

  4. 解题报告:luogu P4180 [BJWC2010]严格次小生成树(次小生成树、倍增LCA优化、O(mlogn) )

    P4180 [BJWC2010]严格次小生成树 次小生成树有两种,一种是不严格次小生成树,也就是可以数值上等于最小生成树,一种是严格次小生成树,是权值严格大于最小生成树,两种求法大同小异. 方法2在严 ...

  5. 最小生成树(kruskal、prim、最小生成森林问题、严格次小生成树)

    整理的算法模板合集: ACM模板 目录 一.kruskal算法 二.prim算法 三.Boruvka算法 四.生成森林问题(K颗树) 五.最小生成树的唯一性 六.严格次小生成树 LCA优化的次小生成树 ...

  6. 一棵树的生成树有几颗_次小生成树(树剖,生成树)

    生成树的概念: 在一个无向图中,设顶点数为\(n\),取其中\(n-1\)条边并使所有点相连,所得到的一棵树即为生成树. 最小生成树: 如果还没有接触过生成树的同学,欢迎戳->最小生成树详解 次 ...

  7. 次小生成树(Prim + Kruaskal)

    问题引入: 我们先来回想一下生成树是如何定义的,生成树就是用n - 1条边将图中的所有n个顶点都连通为一个连通分量,这样的边连成子树称为生成树. 最小生成树很明显就是生成树中权值最小的生成树,那么我们 ...

  8. POJ 1679 - The Unique MST(次小生成树)

    题目链接 https://vjudge.net/problem/POJ-1679 Given a connected undirected graph, tell if its minimum spa ...

  9. BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增)

    1977: [BeiJing2010组队] 次小生成树 Tree Time Limit: 10 Sec Memory Limit: 512 MB Description 小 C 最近学了很多最小生成树 ...

最新文章

  1. 关于chrome等浏览器不支持showModalDialog的解决方案
  2. SVD、SVD++和Asymmetric SVD 以及实例
  3. 【微信小程序企业级开发教程】界面刷新获取新更新数据
  4. python中的字符串常用函数
  5. 秀尔算法:破解RSA加密的“不灭神话” --zz
  6. 分布式技术比较(RPC,CORBA,WebService)
  7. nusoap php 7,nusoap-用php的NuSoap 访问webservice遇到的问题。
  8. 读入自然数m、n,判断m/n是有限小数还是循环小数
  9. 诗和远方:无题(四十九)
  10. bootstrap 模态窗口按钮位置_Bootstrap模态框(modal)垂直居中
  11. nds android7.0模拟器,NDS用MD模拟器jEnesisDS 0.7
  12. 练习 fullpage
  13. 小米无线路由器服务器用户名和密码忘了,小米路由器无线密码(wifi密码)忘记了怎么办? | 192路由网...
  14. linux系统 ifconfig 命令无法找到
  15. HTML实现遮罩层的方法 HTML中如何使用遮罩层
  16. 51单片机两只老虎 c语言,基于51单片机做音乐盒(两只老虎)
  17. ProtoBuf - Arena
  18. maven项目中,添加依赖后,出现Dependency 'xxxx‘ not found解决过程
  19. ORBSLAM3中的MLPnP在重定位时计算当前帧和候选帧的位姿变换
  20. 基于java+springboot+mybatis+vue+elementui的口红电子购物商城

热门文章

  1. 赫夫曼树的原理和构建
  2. Regular、Normal、Medium、Light 对应的font-weight值
  3. 微信小程序之2048小游戏(一)
  4. android 设置圆角边框下边没起作用,Android布局实现圆角边框效果
  5. 外刊阅读——英国女王新冠病毒检测呈阳性
  6. java中 会话的定义_Java Mail核心类中,( )类定义了一个基本的邮件会话。_学小易找答案...
  7. 重庆大学计算机学院可以直博吗,重庆大学2020年推免研究生(含直博生)拟录取名单统计分析...
  8. WEEE电子产品回收注册
  9. js如何将最大值和最小值之间的数划分为五个添加进新数组
  10. 查询计算机系和英语系的学生信息,MySQL练习题1