题目描述

在X星球上有N个国家,每个国家占据着X星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。 
X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖。A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路。 
同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。 
现在告诉你发生在X星球的战事,需要你处理一些关于国家首都的信息,具体地,有如下3种信息需要处理: 
1、A x y:表示某两个国家发生战乱,战胜国选择了x城市和y城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。 
2、Q x:询问当前编号为x的城市所在国家的首都。 
3、Xor:询问当前所有国家首都编号的异或和。

输入

第一行是整数N,M,表示城市数和需要处理的信息数。 
接下来每行是一个信息,格式如题目描述(A、Q、Xor中的某一种)。

输出

输出包含若干行,为处理Q和Xor信息的结果。

样例输入

10 10
Xor
Q 1
A 10 1
A 1 4
Q 4
Q 10
A 7 6
Xor
Q 7
Xor

样例输出

11
1
1
1
2
6
2


题解

LCT维护子树信息(+启发式合并)

这道题也真是强啊,分析了一会码了一会,结果却因为一个傻x错误坑了我一个多小时~

首先,在link时,要把点数少的连接到点数多的上(这其实不应该叫做启发式合并吧)

这样有什么好处?它有两个重要的性质:

1.合并后的重心一定在点数多的树之内,且在连接点到原重心的链上(因为如果在点数少的树之内,重心最后一段的移动路径一定对答案的贡献恒为负,一定不是最优解;而偏移方向不为到连接点方向的话对答案贡献也一定为负)

2.合并后的重心与原重心距离一定不超过点数少的树的点数(假设一个一个插入,偏移距离一定不超过1)

这就可以看出这样做的优势:性质1限定了重心移动的方向,性质2限定了重心移动的距离。

我们考虑:重心发生改变,把它移动的路径分为每次一条边的段,那么每一段对于答案的贡献一定是递减的,直到某一段对答案贡献为负则停止。

那么我们就可以模拟这个过程,将重心设为树根,每次把重心可能的移动路径拿出来,一个一个判断并处理。

嘴上说真简单

实际上,要动态维护子树大小,需要使用LCT维护子树信息。而在LCT中取出重心的移动路径并不是特别容易,需要求出Splay Tree的中序遍历,就要dfs整棵Splay Tree,并在超过范围时停止。

由于重心是固定的,因此将x合并到y上时不能makeroot(y),只能access(y),splay(y)

更复杂的问题是题目不是使用spj,而是强制要求有多个重心时需要选择编号较小的。所以还应该判断编号的影响。

最重要的是,findroot和dfs时都需要pushdown!一开始我在findroot时想起来了,结果到dfs时又忘了,因为这个sb错误zz了一个小时真是气。

代码不是很美观...具体实现可以参考 bzoj4530

时间复杂度依然是$O(n\log^2n)$

#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int fa[N] , c[2][N] , rev[N] , si[N] , sum[N] , sta[N] , top , s;
char str[5];
void pushup(int x)
{
sum[x] = sum[c[0][x]] + sum[c[1][x]] + si[x] + 1;
}
void pushdown(int x)
{
if(rev[x])
{
int l = c[0][x] , r = c[1][x];
swap(c[0][l] , c[1][l]) , swap(c[0][r] , c[1][r]);
rev[l] ^= 1 , rev[r] ^= 1 , rev[x] = 0;
}
}
bool isroot(int x)
{
return c[0][fa[x]] != x && c[1][fa[x]] != x;
}
void update(int x)
{
if(!isroot(x)) update(fa[x]);
pushdown(x);
}
void rotate(int x)
{
int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;
if(!isroot(y)) c[c[1][z] == y][z] = x;
fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
pushup(y) , pushup(x);
}
void splay(int x)
{
update(x);
while(!isroot(x))
{
int y = fa[x] , z = fa[y];
if(!isroot(y))
{
if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int t = 0;
while(x) splay(x) , si[x] += sum[c[1][x]] - sum[t] , c[1][x] = t , pushup(x) , t = x , x = fa[x];
}
int find(int x)
{
access(x) , splay(x);
while(c[0][x]) pushdown(x) , x = c[0][x];
return x;
}
void makeroot(int x)
{
access(x) , splay(x) , swap(c[0][x] , c[1][x]) , rev[x] = 1;
}
void split(int x , int y)
{
makeroot(x) , access(y) , splay(y);
}
void link(int x , int y)
{
split(x , y) , fa[x] = y , si[y] += sum[x];
}
void dfs(int x)
{
if(!x) return;
pushdown(x);
dfs(c[0][x]);
if(top > s) return;
sta[++top] = x;
if(top > s) return;
dfs(c[1][x]);
}
int main()
{
int n , m , i , ret = 0 , x , y , t , tx , ty , r , ts;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) sum[i] = 1 , ret ^= i;
while(m -- )
{
scanf("%s" , str);
if(str[0] == 'A')
{
scanf("%d%d" , &x , &y) , tx = find(x) , ty = find(y) , ret ^= tx ^ ty , splay(tx) , splay(ty);
if(sum[tx] > sum[ty] || (sum[tx] == sum[ty] && x < y)) swap(x , y) , swap(tx , ty);
s = sum[tx] , ts = sum[tx] + sum[ty] , link(x , y) , access(x) , splay(ty);
top = 0 , dfs(ty) , r = ty;
for(i = 1 ; i <= top ; i ++ )
{
splay(sta[i]) , t = si[sta[i]] + 1 + sum[c[1][sta[i]]];
if(ts - t < t || (ts - t == t && sta[i] <= r)) r = sta[i];
else break;
}
makeroot(r) , ret ^= r;
}
else if(str[0] == 'Q') scanf("%d" , &x) , printf("%d\n" , find(x));
else printf("%d\n" , ret);
}
return 0;
}

【bzoj3510】首都 LCT维护子树信息(+启发式合并)的更多相关文章

  1. 【BZOJ3510】首都 LCT维护子树信息+启发式合并

    [BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...

  2. bzoj3510 首都 LCT 维护子树信息+树的重心

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...

  3. 【LCT维护子树信息】uoj207 共价大爷游长沙

    这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate, ...

  4. 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息

    题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量 ...

  5. 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息

    题目描述 给出一棵树和一个点对集合S,多次改变这棵树的形态.在集合中加入或删除点对,或询问集合内的每组点对之间的路径是否都经过某条给定边. 输入 输入的第一行包含一个整数 id,表示测试数据编号,如第 ...

  6. 共价大爷游长沙 lct 维护子树信息

    这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边. 某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的. 现在我们要判断所有的路径是不是都经过 u -> v 我们以u为 ...

  7. $LCT$维护子树信息学习笔记

    \(LCT\)维护子树信息学习笔记 昨天\(FDF\)好题分享投了 \([ZJOI2018]\)历史 这题. 然后我顺势学学这个姿势. 结果调了一年...于是写个笔记记录一下. 基本原理 比较显然地, ...

  8. 洛谷4219 BJOI2014大融合(LCT维护子树信息)

    QWQ 这个题目是LCT维护子树信息的经典应用 根据题目信息来看,对于一个这条边的两个端点各自的\(size\)乘起来,不过这个应该算呢? 我们可以考虑在LCT上多维护一个\(xv[i]\)表示\(i ...

  9. LCT维护子树信息

    有些题目,在要求支持link-cut之外,还会在线询问某个子树的信息.LCT可以通过维护虚边信息完成这个操作. 对于LCT上每个节点,维护两个两sz和si,后者维护该点所有虚儿子的信息,前者维护该点的 ...

随机推荐

  1. python学习总结---网络编程

    网络编程 相关概念 - OSI七层模型:它从低到高分别是:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. - TCP/IP: 在OSI七层模型基础上简化抽象出来的一套网络协议簇,现在得到 ...

  2. spring boot 线程池配置

    1.配置类 package cn.com.bonc.util; import java.util.concurrent.Executor; import java.util.concurrent.Th ...

  3. CentOS环境安装JDK(二)

    安装JDK-7u79-linux-x64 打开虚拟机,进入终端: 1.假设用户名是tianjiale(则需要进入管理员角色,既root) (1).将用户名tianjiale添加到sudoer列表中 提 ...

  4. ThinkPHP5作业管理系统中处理学生未交作业与已交作业信息

    在作业管理系统中,学生登陆到个人中心后可以通过左侧的菜单查看自己已经提交的作业和未提交作业.那么在系统中如何实现这些数据的查询的呢?首先我们需要弄清楚学生(Student).班级(class).作业提 ...

  5. PAT——乙级1015/甲级1062:德才论

    这两个题是一模一样的 1015 德才论 (25 point(s)) 宋代史学家司马光在<资治通鉴>中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德 ...

  6. final 内部类 static

    [Java中为什么会有final变量]: final这个关键字的含义是“这是无法改变的”或者“终态的”: 那么为什么要阻止改变呢? java语言的发明者可能由于两个目的而阻止改变: 1).效率问题: ...

  7. Python 并发编程:PoolExecutor 篇

    个人笔记,如有疏漏,还请指正. 使用多线程(threading)和多进程(multiprocessing)完成常规的并发需求,在启动的时候 start.join 等步骤不能省,复杂的需要还要用 1-2 ...

  8. 牛客网/LeetCode/七月在线/HelloWorld114

    除了知乎,还有这些网站与offer/内推/秋招/春招相关. 其中HelloWorld114更是囊括许多IT知识. 当然,我们可以拓宽思考的维度,既然课堂上的老师讲不好,我们可以自己找资源啊= => ...

  9. [android]不解锁刷机

    本人因为误操作进入andriod recovery模式,显示failed to boot 2,致手机无法恢复出厂值, 当时那叫一个郁闷.上论坛搜寻无数,唉让刷底包的无数(在此不解释),万恶的刷底包. ...

  10. 在网站中配置MIME类型

    经常会遇到这样的情况,某种类型的文件不能够正常下载,*.7z,自定义的文件类型等,需要在配置文件里配置后才能正常下载. 打开Web.Config文件: <system.webServer> ...