「雅礼集训 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}$表 ...
随机推荐
- Idea中新建maven项目的目录结构
maven项目的目录结构如下所示 pom.xml文件内容如下所示 <?xml version="1.0" encoding="UTF-8"?> &l ...
- thinkphp框架部署出现404解决
1:虚拟机配置文件修改: location / { index index.php index.html; if (!-e $request_filename) { rewrite ^/index.p ...
- mac 安装 php7 及扩展
mac 版本号:10.12.3 (16D30) 安装内容 php7.0.18(配置apache),composer,phpunit,xdebug扩展,docopts,mongo和redis扩展 php ...
- python使用Flask作为MockServer的方法
日常开发/测试过程中,需要对相关服务添加挡板--Mock 简单介绍一下使用python的Flask插件,对相关的服务进行Mock # coding:utf-8 import os from flask ...
- C++ 数组操作符重载、函数对象分析、赋值操作符
string类型访问单个字符 #include <iostream> #include <string> #include <sstream> using name ...
- 03 Linux下运行Django项目
1.安装windows和linux传输文件的工具 pip install lrzsz 提供两个命令 一个是上传一个是下载 rz 接收 直接rz sz 上传 直接sz 或者直接拖拽 2.在线下载资源的命 ...
- 10 Scrapy框架持久化存储
一.基于终端指令的持久化存储 保证parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作. 执行输出指定格式进行存储:将爬取到的 ...
- React前端有钱途吗?《React+Redux前端开发实战》学起来
再不学React就真的跟不上大前端的形式了,目前几乎所有前端的招聘条件都是精通React者优先,看看拉勾网的React薪资,都是15K-20K,这个暑假,必须动起来了. 如果你熟悉JavaScript ...
- shell 里面的计算
---恢复内容开始--- 关于shell里面的计算其实早在接触LINUX的时候就已经接触到了.每次在运用的时候却是在网上到处找,所以觉得花点时间好好研究下. 首先了解下常用的算数运算符号: + - ...
- 常用的排序算法介绍和在JAVA的实现(一)
一.写随笔的原因:排序比较常用,借此文介绍下排序常用的算法及实现,借此来MARK一下,方便以后的复习.(本人总是忘得比较快) 二.具体的内容: 1.插入排序 插入排序:在前面已经排好序的序列中找到合适 ...