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

86 篇文章 0 订阅
28 篇文章 0 订阅

题意

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

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

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

题解

没有2操作的做法

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

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

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

有操作2的做法

这个比较牛逼。我们将一个点的颜色染在他与他父亲的边上(根节点造一个没有颜色的父亲出来),然后考虑维护“边连通块”。
边连通块的求法很简单。将每个颜色开一颗树,每个点在其对应颜色的树上与父亲有边,其余颜色无边。这样我们就得到了若干个边连通块。注意有用的点数实则是2n的。

本来这种操作用lct是很好实现的,但是为了恶心的操作二,我们需要使用ETT维护每个连通块的括号序。

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

  • 查询操作:在x的颜色树上,找到x的祖先y,满足color[fa[y]]!=color[x],y的整颗子树就是x所在的点连通块。找到y的这个操作可以通过维护深度最小值,并且在splay上二分,splay(x)后找到x前的第一个比根小1的点即可。

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

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

代码

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值