jzoj6444 树高 (维护边连通块的点染色问题)

题意

一棵树,请支持以下三个操作:

  1. 修改某个点的颜色
  2. 修改某个点所在同色连通块的颜色
  3. 查询某个点所在同色连通块的点数与深度max,深度min.

n 1 0 5 30 n\leq 10^5,颜色数\le30

题解

没有2操作的做法

使用LCT维护重链,并保证重链上所有点颜色相同。通过虚边传递每种颜色的子树大小和深度max。

下文的access(x)操作与一般的access操作不同,一旦access到一条与x颜色不同的链即停止。

修改操作:access(x),access(fa[x]). 直接修改x,更新fa[x]。
查询操作:access(x),splay(x),通过x的实边+虚边信息求答案。

有操作2的做法

这个比较牛逼。我们将一个点的颜色染在他与他父亲的边上(根节点造一个没有颜色的父亲出来),然后考虑维护“边连通块”。可以发现,点连通块一定是边连通块的根的某颗子树。
换句话说,一个连通块除了根之外的所有点都是同颜色的。为了支持切子树,加子树操作,使用若干颗ETT维护每个连通块的括号序。(还有回答询问所需的信息)

  • 修改操作:可以发现,修改操作最多会影响常数个边连通块。进行对应的树形态修改操作即可。

  • 查询操作:找到x的祖先y,满足y是边连通块根的儿子,这个儿子的整颗子树就是x所在的边连通块。找到x的这个操作可以通过维护深度最小值,并且在splay上二分,splay(x)后找到x前的第一个深度为2的点即可。

  • 连通块改色操作:
    这是本题最鬼畜的部分。首先可以发现,更改一个连通块的颜色,就相当于要将其与其他的一些边连通块合并。(这个合并操作实质仍然是一些子树增删操作)。并且合并的总次数不会超过O(n + m),因为修改颜色只会分开一个连通块。接下来的工作就只是去找出所有需要修改的边。通过在splay上维护子树内是否有节点的颜色为c,然后再据此遍历splay完成合并操作。

复杂度应当是 O ( n log n C ) O(n \log n\cdot C) ,常数当然是很大的

代码

可以发现题解下藏着无数细节
这辈子都不可能打的

发布了266 篇原创文章 · 获赞 93 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/104033238
今日推荐