题目链接

问题分析

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

  • 如果一棵树的直径两个端点为\(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维护树的形态即可。如果需要树的直径性质的证明,可以在下方留言。

参考程序

#include <bits/stdc++.h>
using namespace std; const int Maxn = 300010;
int Father[ Maxn ], Child[ Maxn ][ 2 ], Stack[ Maxn ], Tag[ Maxn ];
int Size[ Maxn ];
int N, Q, Rec[ Maxn ][ 2 ], Fa[ Maxn ], Type; void Collect( int Ind ) {
Size[ Ind ] = Size[ Child[ Ind ][ 0 ] ] + Size[ Child[ Ind ][ 1 ] ] + 1;
return;
}
void TagOn( int Ind ) {
Tag[ Ind ] ^= 1;
swap( Child[ Ind ][ 0 ], Child[ Ind ][ 1 ] );
return;
}
void TagDown( int Ind ) {
if( Tag[ Ind ] ) {
TagOn( Child[ Ind ][ 0 ] );
TagOn( Child[ Ind ][ 1 ] );
Tag[ Ind ] ^= 1;
}
return;
}
bool IsRoot( int Ind ) {
if( Ind == 0 ) return true;
return !( ( Child[ Father[ Ind ] ][ 0 ] == Ind ) || ( Child[ Father[ Ind ] ][ 1 ] == Ind ) );
}
void Rotate( int C ) {
int B = Father[ C ];
int A = Father[ B ];
int Tag = Child[ B ][ 1 ] == C;
if( !IsRoot( B ) ) Child[ A ][ Child[ A ][ 1 ] == B ] = C;
Father[ C ] = A;
Child[ B ][ Tag ] = Child[ C ][ Tag ^ 1 ];
Father[ Child[ C ][ Tag ^ 1 ] ] = B;
Child[ C ][ Tag ^ 1 ] = B;
Father[ B ] = C;
Collect( B ); Collect( C );
return;
}
void Splay( int Ind ) {
if( Ind == 0 ) return;
int Num = 0; Stack[ ++Num ] = Ind; int Temp = Ind;
while( !IsRoot( Temp ) ) {
Temp = Father[ Temp ];
Stack[ ++Num ] = Temp;
}
for( int i = Num; i >= 1; --i ) TagDown( Stack[ i ] );
while( !IsRoot( Ind ) ) {
int X = Father[ Ind ];
int Y = Father[ X ];
if( !IsRoot( X ) )
if( ( Child[ Y ][ 0 ] == X ) ^ ( Child[ X ][ 0 ] == Ind ) )
Rotate( Ind );
else
Rotate( X );
Rotate( Ind );
}
Collect( Ind );
return;
}
void Access( int Ind ) {
for( int i = 0; Ind; i = Ind, Ind = Father[ Ind ] ) {
Splay( Ind ); Child[ Ind ][ 1 ] = i; Collect( Ind );
}
return;
}
void MakeRoot( int Ind ) {
Access( Ind );
Splay( Ind );
TagOn( Ind );
return;
}
int FindRoot( int Ind ) {
Access( Ind ); Splay( Ind );TagDown( Ind );
while( Child[ Ind ][ 0 ] ) {
Ind = Child[ Ind ][ 0 ]; TagDown( Ind );
}
Splay( Ind );
return Ind;
}
void Split( int x, int y ) {
MakeRoot( x );
Access( y );
Splay( y );
return;
}
void Link( int x, int y ) {
MakeRoot( x );
if( FindRoot( y ) == x ) return;
Father[ x ] = y;
return;
}
void Cut( int x, int y ) {
MakeRoot( x );
if( FindRoot( y ) != x || Child[ y ][ 0 ] || Father[ y ] != x ) return;
Father[ y ] = Child[ x ][ 1 ] = 0;
Collect( x );
return;
} int GetFather( int x ) {
if( Fa[ x ] == x ) return x;
Fa[ x ] = GetFather( Fa[ x ] );
return Fa[ x ];
} int main() {
scanf( "%d", &Type );
scanf( "%d%d", &N, &Q );
for( int i = 1; i <= N; ++i ) {
Fa[ i ] = i;
Size[ i ] = 1;
Rec[ i ][ 0 ] = Rec[ i ][ 1 ] = i;
}
int LastAns = 0;
for( int i = 1; i <= Q; ++i ) {
int Opt; scanf( "%d", &Opt );
if( Opt == 1 ) {
int u, v; scanf( "%d%d", &u, &v );
if( Type ) u ^= LastAns, v ^= LastAns;
int U = GetFather( u ), V = GetFather( v );
if( U == V ) continue; int Max = 0, x, y;
Split( Rec[ U ][ 0 ], Rec[ U ][ 1 ] );
if( Size[ Rec[ U ][ 1 ] ] > Max ) {
Max = Size[ Rec[ U ][ 1 ] ];
x = Rec[ U ][ 0 ]; y = Rec[ U ][ 1 ];
}
Split( Rec[ V ][ 0 ], Rec[ V ][ 1 ] );
if( Size[ Rec[ V ][ 1 ] ] > Max ) {
Max = Size[ Rec[ V ][ 1 ] ];
x = Rec[ V ][ 0 ]; y = Rec[ V ][ 1 ];
}
Link( u, v ); Fa[ U ] = V;
for( int j = 0; j < 2; ++j )
for( int k = 0; k < 2; ++k ) {
Split( Rec[ U ][ j ], Rec[ V ][ k ] );
if( Size[ Rec[ V ][ k ] ] > Max ) {
Max = Size[ Rec[ V ][ k ] ];
x = Rec[ U ][ j ]; y = Rec[ V ][ k ];
}
}
Rec[ V ][ 0 ] = x; Rec[ V ][ 1 ] = y;
} else {
int u; scanf( "%d", &u );
if( Type ) u ^= LastAns;
int U = GetFather( u );
LastAns = 0;
for( int j = 0; j < 2; ++j ) {
Split( Rec[ U ][ j ], u );
LastAns = max( LastAns, Size[ u ] );
}
--LastAns;
printf( "%d\n", LastAns );
fflush( stdout );
}
}
return 0;
}

「雅礼集训 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. 正则爬取某段子网站前20页段子(request库)

    首先还是谷歌浏览器抓包对该网站数据进行分析,结果如下: 该网站地址:http://www.budejie.com/text 该网站数据都是通过html页面进行展示,网站url默认为第一页,http:/ ...

  2. 2019中山纪念中学夏令营-Day14 图论初步【dijkstra算法求最短路】

    Dijkstra是我学会的第一个最短路算法,为什么不先去学SPFA呢?因为我在luogu上翻到了一张比较神奇的图: 关于SPFA -它死了 以及网上还有各位大佬的经验告诉我:SPFA这玩意很容易被卡. ...

  3. Spring 自定义注解,结合AOP,配置简单日志注解 (转)

    java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致. 下面会讲解Spring中自定义注解的简单流程,其中会涉及到spring框架中的AOP(面向切面编程)相关概念. ...

  4. Robot Framework(二)访问数据库

    1.在Test suit中添加Library 直接输入库名,点击确定即可 DatabaseLibrary BuiltIn 2.在用例中,连接数据库,并执行sql Connect To Database ...

  5. Cypher查询在Neo4j中加载具有点数据类型属性的CSV文件

    我有一个CSV文件,标有3列,ID,纬度,经度.我想将CSV文件加载到Neo4j中并创建具有上述属性的节点.Location:属性应该是具有纬度和经度子属性的点数据类型. CSV是: ID,latit ...

  6. bzoj 3837 pa2013 Filary

    bzoj 先搞第一问.考虑简单情况,如果\(m=2\),那么一定有个剩余类大小\(\ge \lceil\frac{n}{2}\rceil\),同时这也是答案下界 然后我们每次随机选出一个数\(a_i\ ...

  7. 从命令行运行postman脚本

    为什么要在命令行中运行 可以在无UI界面的服务器上运行 可以在持续集成系统上运行 运行准备 导出collection 安装nodejs和npm(或cnpm) 安装Newman 运行及生成测试报告支持4 ...

  8. Centos7 初始化

    systemctl disable firewalld sed -ri '/^[^#]*SELINUX=/s#=.+$#=disabled#' /etc/selinux/config grubby - ...

  9. iptables 设置特定IP访问指定端口

    一.添加规则:设置禁止所有IP访问指定端口8075 [root@zabbix_server ~]# iptables -I INPUT -p tcp --dport -j DROP 二.测试telne ...

  10. SVN 安装教程

    安装包:http://pan.baidu.com/s/1kTTcbJp 安装步骤看这个博主的就好了: http://www.cnblogs.com/xing901022/p/4399382.html ...