在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题。。。。。。

这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦。

贪心排序按一个关键字从小到大枚举边,维护另一个关键字的最小生成树,这样的思路真是太巧妙啦。(然而没有题解的滋养我什么也干不了)

只是关于写法上面,我又有些和Dalao们不一样的地方(因为是自己乱写的)。

link和cut好像脱离了传统意义,本蒟蒻用了link(x)表示将编号为x的边加入用LCT维护的最小生成树,cut(x)反之。

link其实是要连两次,因为要严格深度递增,就让边的一个端点的父亲指向这个代表边的点(轻边),再让代表边的点的父亲指向边的另一个端点(还是轻边)。当然啦,深度大的那个点要先makeroot,不然会影响正确性。

cut就是断两次了,把代表边的点下面那个点(深度大的)access,splay(代表边的点),此时两个端点一个深度小,在左边,一个深度大,在右边,左右儿子全断掉就OK。

其实常规link,cut没问题啊,我也不知道什么时候脑袋短路搞出这种不成熟的写法,不过稍微算算,实际操作量少了些,比起两遍link或cut常数会小一点。

update:这种link和cut可能存在问题。。。还是要写两遍(不知道当时怎么过的)

不过说到常数又留下一个败笔——这一题较特殊,维护连通性可以用并查集,避免了大量findroot(虽然不会T而已)。只是我没有写。findroot真慢呀!以后还是要记住这个小细节。

代码还是放一下

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<algorithm>
  4. using namespace std;
  5. #define R register int
  6. #define I inline void
  7. #define lc c[x][0]
  8. #define rc c[x][1]
  9. #define G ch=getchar()
  10. #define min2(x,y) if(x>y)x=y;
  11. const int N=200000,P=131072;
  12. //P是用来区分点和边的,边的编号在LCT中不变,点的编号全部加上P(为压常用了这样一个数,加上位或运算)
  13. int f[N],c[N][2],mx[N];
  14. bool r[N];
  15. I in(R&z){
  16. register char G;
  17. while(ch<'-')G;
  18. z=ch&15;G;
  19. while(ch>'-')z*=10,z+=ch&15,G;
  20. }
  21. struct EDGE{
  22. int u,v,a,b;
  23. inline bool operator<(EDGE x)const{
  24. return a<x.a;
  25. }
  26. I read(){
  27. in(u);in(v);in(a);in(b);
  28. u|=P;v|=P;//编号变化
  29. }
  30. }e[N];//边放进结构体
  31. inline bool nroot(R x){
  32. return c[f[x]][0]==x||c[f[x]][1]==x;
  33. }
  34. I pushup(R x){
  35. mx[x]=x;
  36. if(e[mx[x]].b<e[mx[lc]].b)mx[x]=mx[lc];
  37. if(e[mx[x]].b<e[mx[rc]].b)mx[x]=mx[rc];//三种情况都要看
  38. }
  39. I pushdown(R x){
  40. if(r[x]){
  41. R t=lc;lc=rc;rc=t;
  42. r[lc]^=1;r[rc]^=1;r[x]=0;
  43. }
  44. }
  45. I pushall(R x){//懒得手写栈,直接用函数堆栈(逃
  46. if(nroot(x))pushall(f[x]);
  47. pushdown(x);
  48. }
  49. I rotate(R x){
  50. R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
  51. if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
  52. f[w]=y;f[y]=x;f[x]=z;
  53. pushup(y);
  54. }
  55. I splay(R x){
  56. R y=x;
  57. pushall(x);
  58. while(nroot(x)){
  59. if(nroot(y=f[x]))
  60. rotate((c[y][0]==x)^(c[f[y]][0]==y)?x:y);
  61. rotate(x);
  62. }
  63. pushup(x);
  64. }
  65. I access(R x){
  66. for(R y=0;x;x=f[y=x])
  67. splay(x),rc=y,pushup(x);
  68. }
  69. I mroot(R x){
  70. access(x);splay(x);
  71. r[x]^=1;
  72. }
  73. inline int froot(R x){
  74. access(x);splay(x);
  75. while(lc)x=lc;
  76. return x;
  77. }
  78. I link(R x){
  79. R y=e[x].u,z=e[x].v;
  80. mroot(z);
  81. f[f[z]=x]=y;
  82. }//非正常link与cut
  83. I cut(R x){
  84. access(e[x].v);splay(x);
  85. lc=rc=f[lc]=f[rc]=0;
  86. pushup(x);
  87. }
  88. int main(){
  89. R n,m,i,y,z,ans=999999;//ans给极大值
  90. in(n);in(m);
  91. for(i=1;i<=m;++i)e[i].read();
  92. sort(e+1,e+m+1);
  93. for(i=1;i<=m;++i)
  94. {
  95. if((y=e[i].u)==(z=e[i].v))continue;
  96. mroot(y);
  97. if(y!=froot(z))link(i);//不联通,直接连
  98. else if(e[i].b<e[mx[z]].b)cut(mx[z]),link(i);//联通,但有更小的边替换
  99. mroot(1|P);
  100. if((1|P)==froot(n|P))min2(ans,e[i].a+e[mx[n|P]].b);//1与n联通就更新答案
  101. }
  102. printf("%d\n",ans==999999?-1:ans);
  103. return 0;
  104. }

洛谷P2387 [NOI2014]魔法森林(LCT,Splay)的更多相关文章

  1. 洛谷P2387 [NOI2014]魔法森林(LCT)

    魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...

  2. 洛谷 P2387 [NOI2014]魔法森林 解题报告

    P2387 [NOI2014]魔法森林 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2 ...

  3. 洛谷P2387 [NOI2014]魔法森林(lct维护最小生成树)

    题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,…,n,边标号为 1,2,3,…, ...

  4. 洛谷P2387 [NOI2014]魔法森林(LCT)

    在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题...... 这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦. 贪心排序按一个关键字 ...

  5. 洛谷 2387 NOI2014魔法森林 LCT

    [题解] 我们先把边按照$a$值从小到大排序,并按照这个顺序加边. 如果当前要加入的边连接的两点$u$与$v$已经是连通的,那么直接加入这条边就会出现环.这时我们需要删除这个环中$b$值最大的边.因此 ...

  6. P2387 [NOI2014]魔法森林 LCT维护最小生成树

    \(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...

  7. 洛谷2387 NOI2014魔法森林(LCT维护最小生成树)

    本题是运用LCT来维护一个最小生成树. 是一个经典的套路 题目中求的是一个\(max(a_i)+max(b_i)\)尽可能小的路径. 那么这种的一个套路就是,先按照一维来排序,然后用LCT维护另一维 ...

  8. [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)

    题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...

  9. 【洛谷P2387】魔法森林

    题目大意:给定一个 N 个点,M 条边的无向图,边有两个边权 a, b,求从 1 号节点到 N 号节点路径的两个权值和的最大值最小是多少. 题解: 对于有两个属性的结构的最优化问题,可以考虑先按照其中 ...

随机推荐

  1. Python md5解密

    这篇文章原来在我盘里存了好久了~    16年9月的.   这 Python的长进没多少啊.现在都17.4了 哎~~ Python之POST提交解密MD5 用易语言写出来md5解密软件后感觉一点成就感 ...

  2. spark集成hbase与hive数据转换与代码练习

    帮一个朋友写个样例,顺便练手啦~一直在做平台的各种事,但是代码后续还要精进啊... import java.util.Date import org.apache.hadoop.hbase.HBase ...

  3. centos7设置静态ip

    动态ip可以上网.静态ip设置成功后,发现不能上网. 1.首先查看动态ip的默认网关 cat /etc/resolv.conf 2.设置配置文件 在 /etc/sysconfig/network-sc ...

  4. css绘制倒三角

    <style> i{ border-left: 5px solid transparent; border-right: 5px solid transparent; border-top ...

  5. PHP系统左侧菜单栏的管理与实现

    在日常的开发工作中,面对后台的日益增长的业务,以及后期业务的迭代开发,通常会选择添加菜单栏的形式来扩充业务功能,同样日益增长的后台菜单选项也为我们后期的维护,产生了一定的困难性.为此我总结出自己关于左 ...

  6. maven项目打包的时候,*Mapper.xml 文件会打不不进去解决办法

    打包的时候,不同版本的 Eclipse 还有IDEA 会有打包打不进去Mapper.xml 文件,这个时候要加如下代码, 在<build> 标签内加入即可 <resources> ...

  7. <script>标签中的 defer 与 async区别

    在html里,使用<script>标签对脚本进行外部或内部引用,<script>标签包含了两个特殊的属性:defer与async,他们的区别如下: 1.若<script& ...

  8. win10外接键盘失灵

    故障描述:笔记本外接的键盘突然之间就失灵,键盘的灯不亮,无法输入 处理方程: 1. 我的电脑右击--> 管理 --> 设备管理器(开始失灵时,键盘下的HID Keyboard Device ...

  9. B. Pyramid of Glasses

    原题链接 B. Pyramid of Glasses Mary has just graduated from one well-known University and is now attendi ...

  10. SpringBoot application.yml logback.xml,多环境配置,支持 java -jar --spring.profiles.active

    趁今天有时间整理了一下 启动命令为 //开发环境 java -jar app.jar --spring.profiles.active=dev--server.port=8060 //测试环境 jav ...