Prelude

快要THUWC了,练一练板子。

传送到LOJ:o(TヘTo)


Solution

首先有一条定理。

到树中任意一点的最远点一定是直径的两个端点之一。

我也不会证反正大家都在用,似乎可以用反证法搞一搞?

然后就是LCT和并查集随便做了。

对于每个连通块,只需要保存这个连通块的直径的两个端点就可以了。

然后合并两个连通块的时候更新一下。


Code

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype> using namespace std;
const int N = 300010;
int _w; int read() {
int x = 0, ch;
while( isspace(ch = getchar()) );
do x = x * 10 + ch - '0';
while( isdigit(ch = getchar()) );
return x;
} int type, n, q, lastans; namespace LCT {
struct Node {
int sz;
Node *ch[2], *pa, *pathpa;
bool rev;
Node() {
ch[0] = ch[1] = pa = pathpa = NULL;
sz = 1, rev = 0;
}
int relation() {
return this == pa->ch[0] ? 0 : 1;
}
Node *pushdown() {
if( rev ) {
rev = 0;
swap( ch[0], ch[1] );
if( ch[0] ) ch[0]->rev ^= 1;
if( ch[1] ) ch[1]->rev ^= 1;
}
return this;
}
Node *maintain() {
sz = 1;
if( ch[0] ) sz += ch[0]->sz;
if( ch[1] ) sz += ch[1]->sz;
return this;
}
Node *rotate() {
if( pa->pa ) pa->pa->pushdown();
pa->pushdown(), pushdown();
Node *old = pa;
int x = relation();
if( pa->pa ) pa->pa->ch[old->relation()] = this;
pa = pa->pa;
old->ch[x] = ch[x^1];
if( ch[x^1] ) ch[x^1]->pa = old;
ch[x^1] = old, old->pa = this;
swap(old->pathpa, pathpa);
return old->maintain(), maintain();
}
Node *splay() {
while( pa ) {
if( !pa->pa ) rotate();
else {
pa->pa->pushdown(), pa->pushdown();
if( relation() == pa->relation() )
pa->rotate(), rotate();
else rotate(), rotate();
}
}
return this;
}
Node *expose() {
Node *rc = splay()->pushdown()->ch[1];
if( rc ) {
ch[1] = rc->pa = NULL;
rc->pathpa = this;
maintain();
}
return this;
}
bool splice() {
if( !splay()->pathpa ) return false;
pathpa->expose()->ch[1] = this;
pa = pathpa, pathpa = NULL;
pa->maintain();
return true;
}
Node *access() {
expose();
while( splice() );
return this;
}
Node *evert() {
access()->rev ^= 1;
return this;
}
};
Node *rt[N];
void init() {
for( int i = 1; i <= n; ++i )
rt[i] = new Node;
}
void link( int u, int v ) {
rt[u]->evert()->pathpa = rt[v];
}
int query( int u, int v ) {
rt[u]->evert();
return rt[v]->access()->sz - 1;
}
} namespace DSU {
int pa[N], du[N], dv[N];
void init() {
for( int i = 1; i <= n; ++i )
pa[i] = du[i] = dv[i] = i;
}
int find( int u ) {
return pa[u] == u ? u : pa[u] = find( pa[u] );
}
int uni( int u, int v ) {
u = find(u), v = find(v);
return pa[u] = v;
}
} namespace Solve {
void init() {
DSU::init();
LCT::init();
}
void link( int u, int v ) {
using DSU::du;
using DSU::dv;
using DSU::find;
int u1 = du[find(u)], u2 = dv[find(u)];
int v1 = du[find(v)], v2 = dv[find(v)];
int w1 = LCT::query(u, u1) > LCT::query(u, u2) ? u1 : u2;
int w2 = LCT::query(v, v1) > LCT::query(v, v2) ? v1 : v2;
LCT::link(u, v);
int rt = DSU::uni(u, v);
int lenu = LCT::query(u1, u2);
int lenv = LCT::query(v1, v2);
int lenw = LCT::query(w1, w2);
// printf( "w1 = %d, w2 = %d, lenw = %d\n", w1, w2, lenw );
if( lenu >= lenv && lenu >= lenw )
du[rt] = u1, dv[rt] = u2;
else if( lenv >= lenu && lenv >= lenw )
du[rt] = v1, dv[rt] = v2;
else
du[rt] = w1, dv[rt] = w2;
// printf( "du = %d, dv = %d\n", du[rt], dv[rt] );
}
int query( int u ) {
using DSU::du;
using DSU::dv;
using DSU::find;
int u1 = du[find(u)], u2 = dv[find(u)];
return max( LCT::query(u, u1), LCT::query(u, u2) );
}
} int main() {
type = read(), n = read(), q = read();
Solve::init();
while( q-- ) {
if( read() == 1 ) {
int u = read(), v = read();
u ^= type * lastans;
v ^= type * lastans;
Solve::link(u, v);
} else {
int u = read();
u ^= type * lastans;
printf( "%d\n", lastans = Solve::query(u) );
}
}
return 0;
}

【题解】【雅礼集训 2017 Day5】远行 LOJ 6038 LCT的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. loj#6040. 「雅礼集训 2017 Day5」矩阵(线性代数+递推)

    题面 传送门 题解 我的线代学得跟屎一样看题解跟看天书一样所以不要指望这题我会写题解 这里 //minamoto #include<bits/stdc++.h> #define R reg ...

  8. [LOJ#6039].「雅礼集训 2017 Day5」珠宝[决策单调性]

    题意 题目链接 分析 注意到本题的 \(C\) 很小,考虑定义一个和 \(C\) 有关的状态. 记 \(f(x,j)\) 表示考虑到了价格为 \(x\) 的物品,一共花费了 \(j\) 元的最大收益. ...

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

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

随机推荐

  1. CentOS 6.7 安装配置 nagios

    一.简介    Nagios是一款开源的免费网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报警,第一时间 ...

  2. 利用python进行简单的图像处理:包括打开,显示以及保存图像

    利用python进行简单的图像处理:包括打开,显示以及保存图像 利用PIL处理 PIL(python image library) 是python用于图片处理的package.但目前这个package ...

  3. c++中的函数重载

    函数多态也称为函数重载. (1)函数重载指的是可以有多个同名的函数,因此对名称进行了重载. (2)函数重载的关键在于函数的参数列表,也称为函数特征标.如果两个函数的参数数目和参数类型相同,同时参数的排 ...

  4. 【大数据应用技术】作业八|爬虫综合大作业Molly134

    本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3075 前言:本次作业是爬取CBO中国票房2010-2019年每年 ...

  5. Alpha版本冲刺(八)

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...

  6. Eclipse下使用Git

    安装Git 有的eclipse已经自带了Git了,就不用安装了. 如果,想重新安装,可以先卸载git,卸载 不同eclipse卸载不一样: 1.在Eclipse中依次点击菜单"Help&qu ...

  7. C++ 类之间的互相调用

    这几天做C++11的线程池时遇到了一个问题,就是类A想要调用类B的方法,而类B也想调用类A的方法 这里为了简化起见,我用更容易理解的观察者模式向大家展开陈述 观察者模式:在对象之间定义一对多的依赖,这 ...

  8. 软工网络15团队作业8——Beta阶段冲刺合集

    博客链接集合 Beta阶段敏捷冲刺计划博客 Beta阶段冲刺第一天 Beta阶段冲刺第二天 Beta阶段冲刺第三天 Beta阶段冲刺第四天 Beta阶段冲刺第五天

  9. 软工网络15团队作业8——Beta阶段敏捷冲刺(Day6)

    提供当天站立式会议照片一张 每个人的工作 1.讨论项目每个成员的昨天进展 赵铭: 数据库整理. 吴慧婷:我的世界界面完成部分. 陈敏: 我的世界功能--学习情况功能完成. 吴雅娟:我的世界功能--学习 ...

  10. NULL,"",String.Empty三者在C#中的区别

    (1)NULLnull 关键字是表示不引用任何对象的空引用的文字值.null 是引用类型变量的默认值.那么也只有引用型的变量可以为NULL,如果int i=null,的话,是不可以的,因为Int是值类 ...