题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977

因为严格,所以要记录到 LCA 的一个次小值;

很快写好,然后改掉一堆错误后终于过了样例!然而交上去1WA;

又改了半天,还是WA,于是放弃,抄题解好久...

然而就在我调了一个小时终于锁定错误就在那个子函数里的时候才突然看到了自己的明显惊天大错误是怎么回事??!!!稍微改了一下下就完美AC。。。

不过还有点收获,把求各种层次的 f 放在 dfs 函数里会比单独拿出来再求一遍快 1000+ms 哦~

题解的写法是直接看 u 到 lca 和 v 到 lca 路上的值,而我是求 lca 的过程中求值的,还是喜欢我的写法;

题解的写法放在注释里了;

囧。

代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. int const maxn=1e5+,maxm=3e5+,inf=1e9;
  8. int n,m,f[maxn][],dep[maxn],mx[maxn][],nmx[maxn][];//
  9. int hd[maxn],ct,fa[maxn],d[maxn],mnn;
  10. ll ans;//ll
  11. bool vis[maxn],used[maxm];
  12. struct P{int u,v,w;}e[maxm];
  13. struct T{
  14. int mx,nmx;
  15. T(int x=,int n=):mx(x),nmx(n) {}
  16. };
  17. struct N{
  18. int to,nxt,w;
  19. N(int t=,int n=,int w=):to(t),nxt(n),w(w) {}
  20. }ed[maxn<<];
  21. bool cmp(P x,P y){return x.w<y.w;}
  22. void add(int x,int y,int w){ed[++ct]=N(y,hd[x],w); hd[x]=ct;}
  23. int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
  24. void dfs(int x)
  25. {
  26. for (int i=; i<=; i++)//写在这里较快
  27. {
  28. if(dep[x]<(<<i))break;
  29. f[x][i]=f[f[x][i-]][i-];
  30. mx[x][i]=max(mx[x][i-],mx[f[x][i-]][i-]);
  31. if (mx[x][i-]==mx[f[x][i-]][i-])
  32. nmx[x][i]=max(nmx[x][i-],nmx[f[x][i-]][i-]);
  33. else
  34. nmx[x][i]=min(mx[x][i-],mx[f[x][i-]][i-]),
  35. nmx[x][i]=max(nmx[x][i],nmx[x][i-]),
  36. nmx[x][i]=max(nmx[x][i],nmx[f[x][i-]][i-]);
  37. }
  38. vis[x]=;
  39. for(int i=hd[x],u;i;i=ed[i].nxt)
  40. if(!vis[u=ed[i].to])
  41. {
  42. f[u][]=x; dep[u]=dep[x]+;
  43. mx[u][]=ed[i].w;
  44. // nmx[u][0]=ed[i].w;//无!
  45. d[u]=ed[i].w;
  46. dfs(u);
  47. }
  48. }
  49. void init()
  50. {
  51. dep[]=; dfs();
  52. // for(int j=1;j<=20;j++)
  53. // for(int i=1;i<=n;i++)
  54. // {
  55. // int tmx=mx[f[i][j-1]][j-1],tnx=nmx[f[i][j-1]][j-1];
  56. // f[i][j]=f[f[i][j-1]][j-1];
  57. // mx[i][j]=max(mx[i][j-1],tmx);
  58. // if(tmx>mx[i][j-1]) nmx[i][j]=max(mx[i][j-1],tnx);
  59. // else if(tmx==mx[i][j-1]) nmx[i][j]=max(nmx[i][j-1],tnx);
  60. // else nmx[i][j]=max(nmx[i][j-1],tmx);
  61. // }
  62. }
  63. void ch(int &rmx,int &rnx,int tmx,int tnx)
  64. {
  65. if(tmx>rmx)
  66. {
  67. rnx=max(tnx,rmx);
  68. rmx=tmx;
  69. }
  70. else if(tmx==rmx) rnx=max(tnx,rnx);
  71. else rnx=max(rnx,tmx);
  72. }
  73. T lca(int x,int y)
  74. {
  75. if(dep[x]<dep[y])swap(x,y);
  76. int k=dep[x]-dep[y],rmx=-,rnx=-;
  77. for(int i=;i>=;i--)
  78. // if((1<<i)&k){rmx=mx[x][i]; rnx=nmx[x][i]; x=f[x][i];}//x放在后面修改!
  79. if((<<i)&k){ch(rmx,rnx,mx[x][i],nmx[x][i]); x=f[x][i];}//!!!!!!囧
  80. for(int i=;i>=;i--)
  81. if(f[x][i]!=f[y][i])
  82. {
  83. ch(rmx,rnx,mx[x][i],nmx[x][i]);
  84. ch(rmx,rnx,mx[y][i],nmx[y][i]);
  85. x=f[x][i]; y=f[y][i]; //后面改!!
  86. }
  87. if(x!=y) ch(rmx,rnx,max(d[x],d[y]),min(d[x],d[y]));
  88. return T(rmx,rnx);
  89. }
  90. //int LCA(int x,int y)
  91. //{
  92. // if(dep[x]<dep[y])swap(x,y);
  93. // int k=dep[x]-dep[y];
  94. // for(int i=20;i>=0;i--)
  95. // if((1<<i)&k){rmx=mx[x][i]; rnx=nmx[x][i]; x=f[x][i];}
  96. // for(int i=20;i>=0;i--)
  97. // if(f[x][i]!=f[y][i])
  98. // {
  99. // x=f[x][i]; y=f[y][i];
  100. // }
  101. // if(x==y)return x;
  102. // return f[x][0];
  103. //}
  104. //T work(int x,int lca)
  105. //{
  106. // T ret;
  107. // int maxx1=-1,maxx2=-1;
  108. // int d=dep[x]-dep[lca];
  109. // for (int i=0; i<=20; i++)
  110. // if (d&(1<<i))
  111. // {
  112. // ch(maxx1,maxx2,mx[x][i],nmx[x][i]);
  113. // x=f[x][i];
  114. // }
  115. // ret.mx=maxx1,ret.nmx=maxx2;
  116. // return ret;
  117. //}
  118. //T solve(int x)
  119. //{
  120. // T ret;
  121. // int u=e[x].u,v=e[x].v,lca=LCA(u,v);
  122. // T uu=work(u,lca);
  123. // T vv=work(v,lca);
  124. // ret.mx=max(uu.mx,vv.mx);
  125. // if(uu.mx>vv.mx) ret.nmx=max(vv.mx,uu.nmx);
  126. // else if(uu.mx==vv.mx) ret.nmx=max(vv.nmx,uu.nmx);
  127. // else ret.nmx=max(uu.mx,vv.nmx);
  128. // return ret;
  129. //}
  130. int main()
  131. {
  132. scanf("%d%d",&n,&m);
  133. for(int i=;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
  134. sort(e+,e+m+,cmp);
  135. for(int i=;i<=n;i++)fa[i]=i;
  136. int cnt=;
  137. for(int i=,u,v;i<=m;i++)
  138. if(find(u=e[i].u)!=find(v=e[i].v))
  139. {
  140. cnt++;
  141. fa[find(u)]=find(v);
  142. used[i]=; ans+=e[i].w;
  143. add(u,v,e[i].w); add(v,u,e[i].w);
  144. if(cnt==n-)break;
  145. }
  146. init();
  147. mnn=inf;
  148. for(int i=;i<=m;i++)
  149. {
  150. if(used[i])continue;
  151. int u=e[i].u,v=e[i].v;
  152. T l=lca(u,v);
  153. // T l=solve(i);
  154. if(e[i].w==l.mx)mnn=min(mnn,e[i].w-l.nmx);
  155. else mnn=min(mnn,e[i].w-l.mx);
  156. }
  157. printf("%lld",ans+mnn);
  158. return ;
  159. }

bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树的更多相关文章

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

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

  2. [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca

    Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...

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

    和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...

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

    题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...

  5. 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)

    传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...

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

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

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

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

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

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

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

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

随机推荐

  1. Java运算符法则

    JAVA运算符法则 运算符是一种特殊的符号,用于表示数据的运算,赋值和比较等: 算术运算符 正号+,负号-,加+,减-,乘*,除/,余或取模%,自增++,自减--,字符串相加+ 正号负号运算符代表运算 ...

  2. wpf 自定义单选按钮 RadioButton

    新建RadioButtonEx.cs public class RadioButtonEx : RadioButton { public Geometry SelectIcon { get { ret ...

  3. numpy.random模块常用函数解析

    numpy.random模块中常用函数解析 numpy.random模块官方文档 1. numpy.random.rand(d0, d1, ..., dn)Create an array of the ...

  4. Linux之 sed用法

    sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法sed命令行格式为:         sed ...

  5. selenium下拉滚动条

    selenium下拉滚动条 制作人:全心全意 谷歌浏览器下拉滚动条 chrome = webdriver.Chrome() //创建谷歌浏览器对象 url="http://www.baidu ...

  6. 利用postman进行接口测试并发送带cookie请求的方法

    做web测试的基本上都用用到postman去做一些接口测试,比如测试接口的访问权限,对于某些接口用户A可以访问,用户B不能访问:比如有时需要读取文件的数据.在postman上要实现这样测试,我们就必要 ...

  7. chrome浏览器安装网页测试插件postman的图文介绍

    用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具.今天给大家介绍的这款网页调试工具不仅可以 ...

  8. 将登录代码模块化,然后用add address接口来调用它,success!

    登录模块,单独写成mylogin()方法,保存为modeltry119.py,然后接口的文件只写接口, 在post请求时,引用mylogin()返回的cookies就好了. requests.post ...

  9. Python基础函数

    join()函数的用法 join()函数连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 语法:'sep'.join(seq) 参数说明sep:分隔符.可以为空 ...

  10. js之循环语句

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...