题目链接

问题分析

要求树上最远距离,很显然就想到了树的直径。关于树的直径,有下面几个结论:

  • 如果一棵树的直径两个端点为\(a,b\),那么树上一个点\(v\)开始的最长路径是\(v\rightarrow a\)或\(v \rightarrow b\)。
  • 如果有两棵树,直径分别为\(a_1,b_1\)和\(a_2,b_2\),那么在这两棵树间连一条边,新树的直径只可能是\(a_1\rightarrow b_1,a_1\rightarrow a_2, a_1\rightarrow b_2, a_2\rightarrow a_1, a_2 \rightarrow b_1, a_2 \rightarrow b_2\)这\(6\)种可能。

那么这道题就是用并查集维护每棵树的直径的两端,然后用LCT维护树的形态即可。如果需要树的直径性质的证明,可以在下方留言。

参考程序

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int Maxn = 300010;
  4. int Father[ Maxn ], Child[ Maxn ][ 2 ], Stack[ Maxn ], Tag[ Maxn ];
  5. int Size[ Maxn ];
  6. int N, Q, Rec[ Maxn ][ 2 ], Fa[ Maxn ], Type;
  7. void Collect( int Ind ) {
  8. Size[ Ind ] = Size[ Child[ Ind ][ 0 ] ] + Size[ Child[ Ind ][ 1 ] ] + 1;
  9. return;
  10. }
  11. void TagOn( int Ind ) {
  12. Tag[ Ind ] ^= 1;
  13. swap( Child[ Ind ][ 0 ], Child[ Ind ][ 1 ] );
  14. return;
  15. }
  16. void TagDown( int Ind ) {
  17. if( Tag[ Ind ] ) {
  18. TagOn( Child[ Ind ][ 0 ] );
  19. TagOn( Child[ Ind ][ 1 ] );
  20. Tag[ Ind ] ^= 1;
  21. }
  22. return;
  23. }
  24. bool IsRoot( int Ind ) {
  25. if( Ind == 0 ) return true;
  26. return !( ( Child[ Father[ Ind ] ][ 0 ] == Ind ) || ( Child[ Father[ Ind ] ][ 1 ] == Ind ) );
  27. }
  28. void Rotate( int C ) {
  29. int B = Father[ C ];
  30. int A = Father[ B ];
  31. int Tag = Child[ B ][ 1 ] == C;
  32. if( !IsRoot( B ) ) Child[ A ][ Child[ A ][ 1 ] == B ] = C;
  33. Father[ C ] = A;
  34. Child[ B ][ Tag ] = Child[ C ][ Tag ^ 1 ];
  35. Father[ Child[ C ][ Tag ^ 1 ] ] = B;
  36. Child[ C ][ Tag ^ 1 ] = B;
  37. Father[ B ] = C;
  38. Collect( B ); Collect( C );
  39. return;
  40. }
  41. void Splay( int Ind ) {
  42. if( Ind == 0 ) return;
  43. int Num = 0; Stack[ ++Num ] = Ind; int Temp = Ind;
  44. while( !IsRoot( Temp ) ) {
  45. Temp = Father[ Temp ];
  46. Stack[ ++Num ] = Temp;
  47. }
  48. for( int i = Num; i >= 1; --i ) TagDown( Stack[ i ] );
  49. while( !IsRoot( Ind ) ) {
  50. int X = Father[ Ind ];
  51. int Y = Father[ X ];
  52. if( !IsRoot( X ) )
  53. if( ( Child[ Y ][ 0 ] == X ) ^ ( Child[ X ][ 0 ] == Ind ) )
  54. Rotate( Ind );
  55. else
  56. Rotate( X );
  57. Rotate( Ind );
  58. }
  59. Collect( Ind );
  60. return;
  61. }
  62. void Access( int Ind ) {
  63. for( int i = 0; Ind; i = Ind, Ind = Father[ Ind ] ) {
  64. Splay( Ind ); Child[ Ind ][ 1 ] = i; Collect( Ind );
  65. }
  66. return;
  67. }
  68. void MakeRoot( int Ind ) {
  69. Access( Ind );
  70. Splay( Ind );
  71. TagOn( Ind );
  72. return;
  73. }
  74. int FindRoot( int Ind ) {
  75. Access( Ind ); Splay( Ind );TagDown( Ind );
  76. while( Child[ Ind ][ 0 ] ) {
  77. Ind = Child[ Ind ][ 0 ]; TagDown( Ind );
  78. }
  79. Splay( Ind );
  80. return Ind;
  81. }
  82. void Split( int x, int y ) {
  83. MakeRoot( x );
  84. Access( y );
  85. Splay( y );
  86. return;
  87. }
  88. void Link( int x, int y ) {
  89. MakeRoot( x );
  90. if( FindRoot( y ) == x ) return;
  91. Father[ x ] = y;
  92. return;
  93. }
  94. void Cut( int x, int y ) {
  95. MakeRoot( x );
  96. if( FindRoot( y ) != x || Child[ y ][ 0 ] || Father[ y ] != x ) return;
  97. Father[ y ] = Child[ x ][ 1 ] = 0;
  98. Collect( x );
  99. return;
  100. }
  101. int GetFather( int x ) {
  102. if( Fa[ x ] == x ) return x;
  103. Fa[ x ] = GetFather( Fa[ x ] );
  104. return Fa[ x ];
  105. }
  106. int main() {
  107. scanf( "%d", &Type );
  108. scanf( "%d%d", &N, &Q );
  109. for( int i = 1; i <= N; ++i ) {
  110. Fa[ i ] = i;
  111. Size[ i ] = 1;
  112. Rec[ i ][ 0 ] = Rec[ i ][ 1 ] = i;
  113. }
  114. int LastAns = 0;
  115. for( int i = 1; i <= Q; ++i ) {
  116. int Opt; scanf( "%d", &Opt );
  117. if( Opt == 1 ) {
  118. int u, v; scanf( "%d%d", &u, &v );
  119. if( Type ) u ^= LastAns, v ^= LastAns;
  120. int U = GetFather( u ), V = GetFather( v );
  121. if( U == V ) continue;
  122. int Max = 0, x, y;
  123. Split( Rec[ U ][ 0 ], Rec[ U ][ 1 ] );
  124. if( Size[ Rec[ U ][ 1 ] ] > Max ) {
  125. Max = Size[ Rec[ U ][ 1 ] ];
  126. x = Rec[ U ][ 0 ]; y = Rec[ U ][ 1 ];
  127. }
  128. Split( Rec[ V ][ 0 ], Rec[ V ][ 1 ] );
  129. if( Size[ Rec[ V ][ 1 ] ] > Max ) {
  130. Max = Size[ Rec[ V ][ 1 ] ];
  131. x = Rec[ V ][ 0 ]; y = Rec[ V ][ 1 ];
  132. }
  133. Link( u, v ); Fa[ U ] = V;
  134. for( int j = 0; j < 2; ++j )
  135. for( int k = 0; k < 2; ++k ) {
  136. Split( Rec[ U ][ j ], Rec[ V ][ k ] );
  137. if( Size[ Rec[ V ][ k ] ] > Max ) {
  138. Max = Size[ Rec[ V ][ k ] ];
  139. x = Rec[ U ][ j ]; y = Rec[ V ][ k ];
  140. }
  141. }
  142. Rec[ V ][ 0 ] = x; Rec[ V ][ 1 ] = y;
  143. } else {
  144. int u; scanf( "%d", &u );
  145. if( Type ) u ^= LastAns;
  146. int U = GetFather( u );
  147. LastAns = 0;
  148. for( int j = 0; j < 2; ++j ) {
  149. Split( Rec[ U ][ j ], u );
  150. LastAns = max( LastAns, Size[ u ] );
  151. }
  152. --LastAns;
  153. printf( "%d\n", LastAns );
  154. fflush( stdout );
  155. }
  156. }
  157. return 0;
  158. }

「雅礼集训 2017 Day5」远行的更多相关文章

  1. LOJ#6038. 「雅礼集训 2017 Day5」远行(LCT)

    题面 传送门 题解 要不是因为数组版的\(LCT\)跑得实在太慢我至于去学指针版的么--而且指针版的完全看不懂啊-- 首先有两个结论 1.与一个点距离最大的点为任意一条直径的两个端点之一 2.两棵树之 ...

  2. 【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目描述 给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. $n\le 3\times 10^5$ ,$ ...

  3. 【刷题】LOJ 6038 「雅礼集训 2017 Day5」远行

    题目描述 Miranda 生活的城市有 \(N\) 个小镇,一开始小镇间没有任何道路连接.随着经济发现,小镇之间陆续建起了一些双向的道路但是由于经济不太发达,在建设过程中,会保证对于任意两个小镇,最多 ...

  4. [loj6038]「雅礼集训 2017 Day5」远行 lct+并查集

    给你 n 个点,支持 m 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. n≤3×10^5 n≤3×10^5 ,m≤5×10^5 m≤5 ...

  5. loj#6038 「雅礼集训 2017 Day5」远行

    分析 代码 #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define ...

  6. loj6038「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目传送门 https://loj.ac/problem/6038 题解 根据树的直径的两个性质: 距离树上一个点最远的点一定是任意一条直径的一个端点. 两个联通块的并的直径是各自的联通块的两条直径的 ...

  7. LOJ#6038. 「雅礼集训 2017 Day5」远行 [LCT维护子树的直径]

    树的直径一定是原联通块4个里的组合 1.LCT,维护树的直径,这题就做完了 2.直接倍增,lca啥的求求距离,也可以吧- // powered by c++11 // by Isaunoya #inc ...

  8. 「雅礼集训 2017 Day5」珠宝

    题目描述 Miranda 准备去市里最有名的珠宝展览会,展览会有可以购买珠宝,但可惜的是只能现金支付,Miranda 十分纠结究竟要带多少的现金,假如现金带多了,就会比较危险,假如带少了,看到想买的右 ...

  9. 「雅礼集训 2017 Day5」矩阵

    填坑填坑.. 感谢wwt耐心讲解啊.. 如果要看这篇题解建议从上往下读不要跳哦.. 30pts 把$A$和$C$看成$n$个$n$维向量,那$A_i$是否加入到$C_j$中就可以用$B_{i,j}$表 ...

随机推荐

  1. MVVM 和 VUE三要素:响应式、模板引擎、渲染

    MVVM 和 VUE三要素:响应式.模板引擎.渲染:https://blog.csdn.net/weixin_37644989/article/details/94409430

  2. session的垃圾回收机制

    session.gc_maxlifetime session.gc_probability session.gc_divisor session.gc_divisor 与 session.gc_pro ...

  3. 矩阵快速幂(Matrix_Fast_Power)

    一.基础知识(1)矩阵乘法 https://blog.csdn.net/weixin_43272781/article/details/82899737 简单的说矩阵就是二维数组,数存在里面,矩阵乘法 ...

  4. 剑指offer-数字在排序数组中出现的次数-数组-python

    题目描述 统计一个数字在排序数组中出现的次数.   python 内置函数 count()一行就能搞定   解题思路 二分查找到给定的数字及其坐标.以该坐标为中点,向前向后找到这个数字的 始 – 终 ...

  5. sql server SQL 服务器 - RDBMS

    SQL 服务器 - RDBMS --现代的 SQL 服务器构建在 RDBMS 之上. DBMS - 数据库管理系统(Database Management System) --数据库管理系统是一种可以 ...

  6. IDEA等全家桶设置Ctrl+滚轮调整字体大小

    File→Settings→General,勾选Change font size... 保存.

  7. 自定义zabbix中的普通KEY及LLD KEY

    普通类型KEY 1.agent端: 编写自定义脚本,脚本需要有输出值返回给zabbix-server,并且给对应脚本赋予zabbix用户可执行权限 zabbix-agnet 且定义key名称和comm ...

  8. 全年DDoS攻击分析|知道创宇云安全2018年度网络安全态势报告

    *本报告由知道创宇云安全出品* 数据来源:知道创宇云防御平台 前言 2018年,网络安全领域暗流涌动,攻击趋势不断攀升,T级DDoS攻击多次爆发.数据泄露事件层出不穷.勒索软件大行其道.此外,随着我国 ...

  9. Oracle DBA 学习总结

    对于学习Oracle 数据库,应该先要了解Oracle 的框架.它有物理结构(由控制文件.数据文件.重做日志文件.参数文件.归档文件.密码文件组成) ,逻辑结构(表空间.段.区.块),内存分配( SG ...

  10. idea中 参数没有描述报错 @param XX tag description is missing错误,去除黄色警告

    最近在使用idea开发工具,在方法备注中参数没有描述报错就会报一些黄色警告: @param XX tag description is missing,下面展示去除黄色警告的方法 File--sett ...