Description
题目链接:Luogu 4299
在 X 星球上有 $n$ 个国家,每个国家占据着 X 星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。
X 星球上战乱频发,如果 A 国打败了 B 国,那么 B 国将永远从这个星球消失,而 B 国的国土也将归 A 国管辖。A 国国王为了加强统治,会在 A 国和 B 国之间修建一条公路,即选择原 A 国的某个城市和 B 国某个城市,修建一条连接这两座城市的公路。
同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。
现在告诉你发生在 X 星球的战事,需要你处理 $m$ 条关于国家首都的信息,具体地,有如下 $3$ 种信息需要处理:
A x y
:表示某两个国家发生战乱,战胜国选择了 $x$ 城市和 $y$ 城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。Q x
:询问当前编号为 $x$ 的城市所在国家的首都。Xor
:询问当前所有国家首都编号的异或和。
数据范围:$2\le n\le 10^5$,$1\le m\le 2\times 10^5$
Solution
用 $\text{LCT}$ 来维护子树信息。这里有一个重心的性质:两棵树合并后的重心一定在原来两个重心的链上。
于是我们考虑对这条路径二分。记 $lsum$ 表示搜索区间左端点以左的子树大小总和,类似的 $rsum$ 表示右端点以右的。当前搜索区间就是子树 $x$,显然 $x$ 作为根把搜索区间分成了左右两块(在 $\text{Splay}$ 中对应 $x$ 的左子树和右子树)。
对于重心的判定:如果 $sz_{x\ \text{的左子树}}+lsum$ 和 $sz_{x\ \text{的右子树}}+rsum$ 都不超过整棵树的大小的一半,那么这个点 $x$ 就是重心。对于总大小是奇数的,重心有且只有 $1$ 个;否则为了得到编号最小的重心,必须继续找下去。
接下来我们要往儿子里寻找答案,我们贪心地选择 $x$ 的儿子节点。如果 $sz_{x\ \text{的左子树}}+lsum<sz_{x\ \text{的右子树}}+rsum$,那么我们进入右儿子;并把 $lsum$ 加上左儿子的总大小和 $x$ 的虚子树大小。反之同理。
由于 $\text{Splay}$ 有很优秀的期望 $O(\log n)$ 的深度,因此每次找重心的复杂度为 $O(\log n)$!
最后提一些细节:
- 在 $\text{LCT}$ 维护子树信息时,$\text{link}$ 操作时会有影响。$y$ 会多出一个轻儿子 $x$,那么 $y$ 的所有祖先的信息都要更新。这是一般写法不能胜任的。我们必须把 $y$ 转到根节点才不会影响正确性。代码中
split(x,y)
是makeroot(x),access(y),splay(y)
的偷懒写法。 - 使用
findroot
找重心太慢了。我们直接用并查集来维护每个点所在树的重心。 - 在二分找重心的过程中,提取子树信息前一定要记得下传标记!
时间复杂度:$O(m\log n)$
Code
1 |
|