严格次小生成树

首先看看如果不严格我们怎么办。

非严格次小生成树怎么做

由此,我们发现一个结论,求非严格次小生成树,只需要先用kruskal算法求得最小生成树,然后暴力枚举非树边,替换路径最大边即可。

那要是严格呢?

我们发现如果是严格的次小生成树,那么将一条边替换另一条时,这两条边的权值一定不相同

但是,我们知道,替换边肯定大于等于被替换边(因为如果替换边小于被替换边,就存在一颗包含替换边而不包含被替换边的一棵权值更小的生成树,原树就不是最小生成树了)

所以替换边要么等于路径上最大的边,要么比最大的边还大。

利用这个性质,我们只需要维护路径中的最大值和次大值,当替换边等于路径上的最大值,我们直接换用严格次大值即可。

一些细节

1.我维护两点之间路径最大值用的是LCT,但是正解是LCA。LCT必须要开O2才能跑过去。

2.数组要开足够大,最后统计答案时要开long long,不然会爆int

我的代码

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <queue>
  7. #define rg register int
  8. #define ll long long
  9. #define RG register
  10. #define il inline
  11. using namespace std;
  12. il ll gi() {
  13. RG ll x=0;rg o=0;RG char ch=getchar();
  14. while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
  15. if(ch=='-') o=1,ch=getchar();
  16. while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  17. return o?-x:x;
  18. }
  19. int n,m;
  20. #define SZ 7000010
  21. struct Edge {int a,b;ll w;}e[SZ];
  22. bool cmp(Edge a,Edge b) {return a.w<b.w;}
  23. #define lson tr[x].ch[0]
  24. #define rson tr[x].ch[1]
  25. struct Splaytree{int fa,ch[2],rev,mxp,mxp2;}tr[SZ];
  26. il void pushup(rg x)
  27. {
  28. tr[x].mxp=x; tr[x].mxp2=0;
  29. if(e[tr[lson].mxp].w>e[tr[x].mxp].w) tr[x].mxp=tr[lson].mxp;
  30. if(e[tr[rson].mxp].w>e[tr[x].mxp].w) tr[x].mxp=tr[rson].mxp;
  31. // 维护 最大
  32. if(e[tr[lson].mxp].w!=e[tr[x].mxp].w && (e[tr[lson].mxp].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[lson].mxp;
  33. if(e[tr[lson].mxp2].w!=e[tr[x].mxp].w && (e[tr[lson].mxp2].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[lson].mxp2;
  34. if(e[tr[rson].mxp].w!=e[tr[x].mxp].w && (e[tr[rson].mxp].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[rson].mxp;
  35. if(e[tr[rson].mxp2].w!=e[tr[x].mxp].w && (e[tr[rson].mxp2].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[rson].mxp2;
  36. // 维护严格次大
  37. }
  38. il void pushdown(rg x)
  39. {
  40. if(tr[x].rev)
  41. {
  42. tr[lson].rev^=1,tr[rson].rev^=1;
  43. swap(lson,rson),tr[x].rev=0;
  44. }
  45. }
  46. il bool isroot(rg x)
  47. {
  48. return tr[tr[x].fa].ch[0]!=x && tr[tr[x].fa].ch[1]!=x;
  49. }
  50. il void rotate(rg x)
  51. {
  52. rg y=tr[x].fa,z=tr[y].fa;
  53. rg k=tr[y].ch[1]==x;
  54. if(!isroot(y)) tr[z].ch[y==tr[z].ch[1]]=x;tr[x].fa=z;
  55. tr[y].ch[k]=tr[x].ch[k^1],tr[tr[x].ch[k^1]].fa=y;
  56. tr[x].ch[k^1]=y,tr[y].fa=x;
  57. pushup(y),pushup(x);
  58. }
  59. int stk[SZ],top;
  60. il void splay(rg x)
  61. {
  62. stk[top=1]=x;
  63. for(rg i=x;!isroot(i);i=tr[i].fa) stk[++top]=tr[i].fa;
  64. for(;top;--top) pushdown(stk[top]);
  65. while(!isroot(x))
  66. {
  67. rg y=tr[x].fa,z=tr[y].fa;
  68. if(!isroot(y))
  69. (tr[y].ch[0]==x)^(tr[z].ch[0]==y)?rotate(x):rotate(y);
  70. rotate(x);
  71. }
  72. }
  73. il void access(rg x) {for(rg y=0;x;y=x,x=tr[x].fa)splay(x),rson=y,pushup(x);}
  74. il void makeroot(rg x) {access(x);splay(x);tr[x].rev^=1;}
  75. il int findroot(rg x) {access(x);splay(x);while(lson) x=lson;return x;}
  76. il void split(rg x,rg y) {makeroot(x);access(y);splay(y);}
  77. il int query(rg x,rg y) {split(x,y);return tr[y].mxp;} //求x 到 y最大值
  78. il int query2(rg x,rg y) {split(x,y);return tr[y].mxp2;} // 求x 到 y严格次大值
  79. il void link(rg x,rg y) {makeroot(x);tr[x].fa=y;}
  80. il void cut(rg x,rg y) {split(x,y);if(tr[y].ch[0]==x)tr[y].ch[0]=tr[x].fa=0;}
  81. int fa[SZ];int find_fa(rg x) {if(x!=fa[x]) fa[x]=find_fa(fa[x]);return fa[x];} //一行并查集
  82. bool check[SZ];
  83. int main()
  84. {
  85. n=gi(),m=gi();
  86. for(rg i=1;i<=m;++i) e[i]=(Edge){gi(),gi(),gi()};
  87. // 先求一遍最小生成树 ans 记录最小生成树边的大小
  88. RG ll ans=0;
  89. sort(e+1,e+1+m,cmp);
  90. for(rg i=1;i<=n;++i) fa[i]=i; // 初始化并查集
  91. for(rg f1,f2,i=1;i<=m;++i)
  92. {
  93. f1=find_fa(e[i].a);
  94. f2=find_fa(e[i].b);
  95. if(f1!=f2)
  96. {
  97. check[i]=1; // check=1 表示最小生成树中有这一条边 反之
  98. fa[f1]=f2;
  99. ans+=e[i].w;
  100. link(e[i].a+m,i);
  101. link(e[i].b+m,i);
  102. }
  103. }
  104. #define INF 2147483647
  105. #define Getmin(a,b) (a)=(a)>(b)?(b):(a)
  106. RG ll Ans=INF;
  107. for(rg f1,f2,i=1;i<=m;++i)
  108. {
  109. if(check[i]) continue; //我们选择不再最小生成树上的边
  110. rg mxp=query(e[i].a+m,e[i].b+m);
  111. if(e[mxp].w==e[i].w)
  112. {
  113. rg mxp2=query2(e[i].a+m,e[i].b+m);
  114. if(!mxp2 || e[mxp2].w==e[mxp].w) continue;
  115. Getmin(Ans,e[i].w-e[mxp2].w);
  116. }
  117. else Getmin(Ans,e[i].w-e[mxp].w);
  118. }
  119. cout<<ans+Ans;
  120. return 0;
  121. }

(luogu4180) [Beijing2010组队]次小生成树Tree的更多相关文章

  1. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  2. 1977: [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...

  3. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

  4. [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 5168  Solved: 1668[S ...

  5. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  6. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  7. BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树

    描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...

  8. 【刷题】BZOJ 1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  9. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

随机推荐

  1. 调试 smallcorgi/Faster-RCNN_TF 的demo过程遇到的问题

    最近在调试faster R-CNN时,遇到了各种各样的问题.使用的算法库为https://github.com/smallcorgi/Faster-RCNN_TF 注:本文使用的是通过virtuale ...

  2. canvas常用api

    1. 在canvas标签中给出长宽(不带单位):<canvas width="600" height="600"></canvas> 或 ...

  3. 【NOIP2015】运输计划

    [NOIP2015]运输计划 标签: 树上差分 LCA 二分答案 Description 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星 ...

  4. 用node.js搭建本地服务器

    我的第一篇笔记来写写node.js,我对node.js的并不是很了解,基本的项目路径变换还是会的.原先我下载node.js就是我想学vue.js,后来因为工作的繁忙搁浅了我的计划.最近在学习phase ...

  5. 五子棋的斜对角方向上的规则 -- java编程(简单粗暴版)

    五子棋判断输赢规则 --- 斜对角线方向上 一.左上右下方向上 1.分析图 2.代码 /**判断左上右下方向上是否有连续五颗相同颜色的棋子 * 全部遍历法 */ int loop = 0; boole ...

  6. 缩减APK包大小

    1)开启minifyEnabled 开启混淆,删除没用的java文件 2)开启shrinkResources 去除无用资源 3)resConfigs "zh" 删除无用的语言资源 ...

  7. 使用CrashHandler来获取应用的crash信息

    源码地址https://github.com/king1039/android-art-res/tree/master/Chapter_13/CrashTest/src/com/ryg/crashte ...

  8. Flask下载文件

    前言 由于最近在做文件管理模块的功能,所以难免会遇到文件上传下载这块的功能.不过文件上传那块是调用的OSS api,所以接触的不多. 文件的下载: 1. 接口返回真实的文件 这种情况比较简单, fla ...

  9. CEPH RGW集群和bucket的zone group 不一致导致的404异常解决 及 使用radosgw-admin metadata 命令设置bucket metadata 的方法

      问题现象: 最近在研究zonegroup的配置操作,发现在配置zonegroup后修改了default zone,导致访问对象报404错误. 问题原因: rgw 日志 报异常'request fo ...

  10. Android开发之仿微信显示更多文字的View

    最近开发需求中要模仿微信朋友圈文章的展开收起功能,网上找了找,发现都有问题,于是乎自己在前辈的基础上进行了一定量的修改,下边将源码贴出来供大家参考:1.主Activity布局文件就不粘贴了,很简单,就 ...