题意
一棵树,请支持以下三个操作:
- 修改某个点的颜色
- 修改某个点所在同色连通块的颜色
- 查询某个点所在同色连通块的点数与深度max,深度min.
题解
没有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完成合并操作。
复杂度应当是 ,常数当然是很大的
代码
可以发现题解下藏着无数细节
这辈子都不可能打的