「雅礼集训 2017 Day5」远行
问题分析
要求树上最远距离,很显然就想到了树的直径。关于树的直径,有下面几个结论:
- 如果一棵树的直径两个端点为\(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」远行的更多相关文章
- LOJ#6038. 「雅礼集训 2017 Day5」远行(LCT)
题面 传送门 题解 要不是因为数组版的\(LCT\)跑得实在太慢我至于去学指针版的么--而且指针版的完全看不懂啊-- 首先有两个结论 1.与一个点距离最大的点为任意一条直径的两个端点之一 2.两棵树之 ...
- 【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT
题目描述 给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. $n\le 3\times 10^5$ ,$ ...
- 【刷题】LOJ 6038 「雅礼集训 2017 Day5」远行
题目描述 Miranda 生活的城市有 \(N\) 个小镇,一开始小镇间没有任何道路连接.随着经济发现,小镇之间陆续建起了一些双向的道路但是由于经济不太发达,在建设过程中,会保证对于任意两个小镇,最多 ...
- [loj6038]「雅礼集训 2017 Day5」远行 lct+并查集
给你 n 个点,支持 m 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. n≤3×10^5 n≤3×10^5 ,m≤5×10^5 m≤5 ...
- loj#6038 「雅礼集训 2017 Day5」远行
分析 代码 #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define ...
- loj6038「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT
题目传送门 https://loj.ac/problem/6038 题解 根据树的直径的两个性质: 距离树上一个点最远的点一定是任意一条直径的一个端点. 两个联通块的并的直径是各自的联通块的两条直径的 ...
- LOJ#6038. 「雅礼集训 2017 Day5」远行 [LCT维护子树的直径]
树的直径一定是原联通块4个里的组合 1.LCT,维护树的直径,这题就做完了 2.直接倍增,lca啥的求求距离,也可以吧- // powered by c++11 // by Isaunoya #inc ...
- 「雅礼集训 2017 Day5」珠宝
题目描述 Miranda 准备去市里最有名的珠宝展览会,展览会有可以购买珠宝,但可惜的是只能现金支付,Miranda 十分纠结究竟要带多少的现金,假如现金带多了,就会比较危险,假如带少了,看到想买的右 ...
- 「雅礼集训 2017 Day5」矩阵
填坑填坑.. 感谢wwt耐心讲解啊.. 如果要看这篇题解建议从上往下读不要跳哦.. 30pts 把$A$和$C$看成$n$个$n$维向量,那$A_i$是否加入到$C_j$中就可以用$B_{i,j}$表 ...
随机推荐
- Jmeter 连接远程测压__(负载测试)
第一步: 双方关闭防火墙 打开jmeter server bat 路径如下 会出错
- python-day29(正式学习)
目录 元类 什么是元类 为什么用元类 内置函数exec class创建类 type实现 自定义元类 _ _ call _ _ _ _ new _ _ 自定义元类控制的实例化 属性查找顺序 元类 警告! ...
- 利用Mocking Framework 单元测试Entity Framework
一.前言 在实际编写程序时,往往需要与数据库打交道,在单元测试中直接使用数据库又显得太重,如果可以方便的编写一些测试数据,这样更易于检测功能.如何模拟数据库行为便是本篇的主题.微软有教程说明Moq E ...
- Keepalived+Nginx+Tomcat 实现高可用Web集群
https://www.jianshu.com/p/bc34f9101c5e Keepalived+Nginx+Tomcat 实现高可用Web集群 0.3912018.01.08 20:28:59字数 ...
- css复杂动画(animation属性)
1.声明:@keyframes name{ }: 2.涉及到的属性 animation-name:动画名称 animation-duration:单次动画总时长 animation-timing- ...
- 第一个简单的Echarts实例
该示例使用 vue-cli 脚手架搭建 安装echarts依赖 npm install echarts -S 或者使用国内的淘宝镜像: 安装 npm install -g cnpm --registr ...
- uploadify 上传文件插件
今天在项目中要用到文件上传功能时,想借助Jquery方式来实现,于是想到用uploadify插件来实现.不经意间在网上看到了一遍关于这个插件的用法,写的很好.在这里就分享给大家,希望对大家有帮助.以下 ...
- chrome 浏览器安装 postman
chrome 浏览器安装 postman(插件下载见文章末尾) 1.安装方法 将下载的crx插件拖拽到chrome浏览器即可安装成功. 2.特殊情况 问题: chrome73版本后拖拽安装chrome ...
- Excel中的常用快捷键
1)工作表之间快速切换 Ctrl+PageUp切换的是当前所在工作表的前一个工作表, Ctrl+PageDown切换的是当前所在工作表的后一个工作表. 2)Ctrl +Home 强迫回到最前一个单元格 ...
- Java高并发程序设计学习笔记(一):并行简介以及重要概念
转自:https://blog.csdn.net/dataiyangu/article/details/86211544#_28 文章目录为什么需要并行?反对意见大势所趋几个重要的概念同步(synch ...