P4180 [BJWC2010]严格次小生成树

次小生成树有两种,一种是不严格次小生成树,也就是可以数值上等于最小生成树,一种是严格次小生成树,是权值严格大于最小生成树,两种求法大同小异。

方法2在严格次小生成树和不严格次小生成树都成立,而方法1只在严格次小生成树中成立

对于任意一颗最小生成树,都存在一个次小生成树(严格或者不严格都成立),与最小生成树只差1条边。

根据存在次小生成树与最小生成树只差一条边。
我们可以先通过kruskal求出最小生成树 O(mlogm)
通过这个树初始化某点到其他点的路径中最大边、次大边。 O(n2)
遍历所有未在树中的边(u–>v), 看是否大于u到v的边的最大值, 若大于那么可以替换这条边,若不大于那就再判断是否大于次值,若大于同理进行替换。因为这里的w一定是不小于最小生成树里的任何一条边的权值,最多会等于,而本题为严格次小生成树,不能等于。

然后本题实际上是整棵最小生成树自建立以来就没有动过,是典型的只要答案不干事,只是全程取min要答案,这样就保证了无后效性和算法的正确性。

本题直接dfs的时间复杂度为O(mlogm+n2+mlogn)O(mlogm + n^2+mlogn)O(mlogm+n2+mlogn)
而本题 nnn 的数据范围达到了500007500007500007 ,所以我们要考虑更高效的方法:
我们使用LCA和倍增代替原本的 dfsdfsdfs(全部遍历)查找最大值和次大值,可以把时间压缩到O(mlogn)O(mlogn)O(mlogn)

快200行的代码敲了我半个小时累死我了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>using namespace std;typedef long long ll;const int N = 500007,M = 1e6 + 7, INF = 0x3f3f3f3f;int n,m;
int ver[M], nex[M], edge[M], head[N], tot;
int fa[N];
int deep[N];
int f[N][20];//lca
int d1[N][20];//注意d1[i][k]是当前i这个点从自己到2^k祖先整个路径上所有边权的的最大值,这样就不会因为lca是跳着走而有漏掉的情况
int d2[N][20];
int q[M];//手写循环队列struct node{int x,y,z;bool used;bool operator<(const node &t)const{return z < t.z;}
}e[M];int Find(int x){if(fa[x] == x)return x;return fa[x] = Find(fa[x]);
}void add(int x,int y,int z){ver[tot] = y;edge[tot] = z;nex[tot] = head[x];head[x] = tot ++ ;
}void bfs(int rt){//bfs把所有的边都覆盖掉的deep[rt] = 1;int hh = 0, tt = 0;q[tt ++ ] = rt;while(hh != tt){int x = q[hh ++ ];if(hh == M)hh = 0;for(int i = head[x];~i;i = nex[i]){int y = ver[i],z = edge[i];if(!deep[y]){deep[y] = deep[x] + 1;q[tt ++ ] = y;if(tt == M)tt = 0;f[y][0] = x;//lca的正常处理d1[y][0] = z;//最大值,初始化为边权d2[y][0] = -INF;//次大值,最开始为-INFfor(int k = 1;k <= 16;++k){int anc = f[y][k - 1];f[y][k] = f[anc][k - 1];//左半边和右半边int distance[4] = {d1[y][k - 1],d2[y][k - 1],d1[anc][k - 1],d2[anc][k - 1]};//这两个要初始化为-INF,一会取最大值d1[y][k] = d2[y][k] = -INF;for(int o = 0;o < 4;++o){int d = distance[o];//老规矩,大于最大,最大给次大,更新最大if(d > d1[y][k])d2[y][k] = d1[y][k],d1[y][k] = d;else if(d != d1[y][k] && d > d2[y][k])//否则看次大,反正d是不可能小于他们d2[y][k] = d;}}}}}
}int lca(int x,int y,int z){//返回差值static int distance[N * 2];//路上经过的全部放到这个数组里取最大值int cnt = 0;if(deep[x] < deep[y])swap(x,y);for(int k = 16;k >= 0;k--){if(deep[f[x][k]] >= deep[y]){distance[cnt ++ ] = d1[x][k];distance[cnt ++ ] = d2[x][k];x = f[x][k];}}if(x != y){for(int k = 16;k >= 0;--k){if(f[x][k] != f[y][k]){distance[cnt ++ ] = d1[x][k];distance[cnt ++ ] = d2[x][k];distance[cnt ++ ] = d1[y][k];distance[cnt ++ ] = d2[y][k];x = f[x][k],y = f[y][k];}}distance[cnt ++ ] = d1[x][0];distance[cnt ++ ] = d1[y][0];//此时x和y距离它们的lca只有一步,也就是只有的d1 = w,而d2 = -INF,不用加}int dist1 = -INF,dist2 = -INF;//按照老规矩更新for(int i = 0;i < cnt ;++i){int d = distance[i];if(d > dist1)dist2 = dist1,dist1 = d;else if(d != dist1 && d > dist2)dist2 = d;}//能换最大值肯定是换最大值更优if(z > dist1)return z - dist1;if(z > dist2)return z - dist2;return INF;//换不了就返回INF,因为我们最后要的是最小值(严格次小生成树)
}ll kruskal(){ll res = 0;for(int i = 1;i <= n;++i)//千万别往了并查集初始化!!!fa[i] = i;sort(e + 1,e + 1 + m);memset(head,-1,sizeof head);for(int i = 1;i <= m;++i){int x = e[i].x,y = e[i].y,z = e[i].z;int fx = Find(x);int fy = Find(y);if(fx != fy){fa[fx] = fy;e[i].used = true;res += z;add(x,y,z);add(y,x,z);}}return res;
}int main(){scanf("%d%d",&n,&m);for(int i = 1;i <= m;++i){int x,y,z;scanf("%d%d%d",&x,&y,&z);e[i] = {x,y,z};}ll sum = kruskal();bfs(1);//lca预处理ll res = 1e18;//会爆intfor(int i = 1;i <= m;++i){if(!e[i].used){//对于所有非树边int x = e[i].x,y = e[i].y, z = e[i].z;res = min(res,sum + lca(x,y,z));}}printf("%lld\n",res);return 0;
}

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

  1. 解题报告(十八)数论题目泛做(Codeforces 难度:2000 ~ 3000 + )

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  2. 【解题报告系列】超高质量题单 + 题解(ACM / OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我新写的超高质量的题解和代码,题目难度不 ...

  3. 解题报告(三)多项式求值与插值(拉格朗日插值)(ACM / OI)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  4. 解题报告(十三)中国剩余定理(ACM / OI)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  5. 解题报告(八) prufer 序列与 Cayley 公式(ACM / OI)超高质量题解

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  6. 解题报告(五)组合计数(ACM / OI)超高质量题解

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  7. 解题报告(二)多项式问题(多项式乘法及其各种运算)(ACM/ OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  8. 解题报告(一)B、(CF453D) Little Pony and Elements of Harmony(FWT经典套路 + 任意模数 k 进制FWT + 快速幂)(2)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  9. 解题报告(一)快速沃尔什变换FWT(ACM / OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

最新文章

  1. BootStrap 智能表单系列 五 表单依赖插件处理
  2. php 多线程上传,PHP多线程(pthreads)参数传递学习笔记
  3. [原]走过2007,我的2008
  4. reactjs redux chrome扩展插件
  5. php socket的一些问题
  6. 我的世界java版tis,我的世界1.7.10~1.8.8 9tis-3d回到汇编的时代mod
  7. 培养沙雕要从娃娃抓起
  8. SQL Server中的表变量
  9. 吝啬的国度(dfs)
  10. java怎么延迟执行语句_Go语言defer(延迟执行语句)
  11. java image to base64_Java实现base64图片编码数据转换为本地图片的方法
  12. SQL Server查看是企业版还是个人版
  13. 从命令行编译 JScript 代码
  14. FANUC机器人的主板结构和电缆连接示意图介绍
  15. 信息安全密码学实验二:序列密码的设计与实现
  16. 论文阅读: 3D Human Pose Estimation in the Wild by Adversarial Learning
  17. 为图片赋值红色或绿色的伪彩 用python、EmguCV、 OpenCvSharp实现
  18. 展讯7731C_M Android6.0 充电指示灯实现(一)------关机充电实现
  19. 学习《笨办法学phyton》(0)
  20. 几何机器学习:如何在基础科学领域成为现实??

热门文章

  1. eclipse中update maven工程后,项目JDK变为1.6
  2. 删除windows7的隐藏分区
  3. 使用MSBuild实现完整daily build流程
  4. 必须要懂得的密码技术
  5. 前端见微知著工具篇:Bower组件管控
  6. Web开发的标准目录结构
  7. 操作无法完成.键入的打印机名不正确,或者指定的打印机没有连接到服务器上.有关详细信息,请单帮助...
  8. 绝对经典的滑轮新闻显示(javascript+css)实现
  9. 挑选适合自己的公司——网络工程师你是否真的已经倒下(二)
  10. GridView直接以excel格式导出到客户端