1 条题解
-
0
题意简化
维护 个集合 ,定义:
$$B_i = \left(\bigcap_{j \in A_i} B_j\right) \cup C_i $$其中:
- 中的元素都
- 所有 两两不相交
已知 和 ,支持:
- 添加新集合 ,给定 和
- 修改
- 查询
,强制在线。
核心思想:树形结构 + LCT
1. 转化为树结构
关键观察: 的定义中,依赖 中所有 的交集。
设 意义上的父亲节点:
- 包含 (大小 )
- 同时包含父节点集合的部分
实际上,可以构建一棵树:
- 节点 对应
- 父节点是 中所有 在树上的最近公共祖先(LCA)
2. 查询公式推导
对于查询 ,要求 。
由于 两两不相交,答案等于:
$$\sum_{i \in S} |C_i| - \sum_{i<j} |B_i \cap B_j| + \dots $$但更简单:在树结构中, 包含从根到 路径上所有节点的 集合。
因此:
$$\left|\bigcup_{i \in S} B_i\right| = \left|\bigcup_{i \in S} (\text{根到 } i \text{ 路径上所有 } C)\right| $$即:所有查询节点到根路径的并集的大小。
3. 算法实现
使用**LCT(Link-Cut Tree)**维护:
节点信息:
val[i]: 的大小sum[i]:子树(Splay树中)的val和
操作:
-
Add:
- 找到 中所有节点在LCT中的LCA
last - 创建新节点
nod++ - 设置父亲
fa[nod] = last val[nod] = k( 大小)access(nod)更新信息
- 找到 中所有节点在LCT中的LCA
-
Update:
- 修改
val[x] - 更新节点信息
- 修改
-
Query:
- 对查询集合 中的每个节点
x:access(x):将根到x的路径变为偏爱路径- 如果节点未被访问过(
vis[x] != tim):- 累加
sum[x]到答案 - 标记已访问
- 累加
- 答案为路径并集的大小
- 对查询集合 中的每个节点
关键技巧
1. LCA计算
代码中
LCA(u,v)通过两次access实现:access(u); return access(v);第二次
access返回的节点就是 LCA。2. 路径去重
使用
vis[]数组和tim时间戳标记已访问的节点,避免重复计算。3. 强制在线处理
- 读入的 中元素需要异或上次答案
lastans - 注意节点编号从 1 开始(
++x)
复杂度分析
- Add: 找 LCA
- Update: Splay 操作
- Query:
- 总复杂度:,可过
样例解释
初始:节点1为根(虚拟节点)
操作1:
Add 0 1- ,LCA 为 1
- 创建节点2,父节点为1,
操作2:
Query 1 1- 查询节点2:路径 {1,2},大小 1
- 输出:1
操作3:
Update 1 4- 修改节点2的
操作4:
Query 1 1- 查询节点2:路径 {1,2},大小 4
- 输出:4
代码特点
- 标准 LCT 实现
vis[]时间戳去重sum[]维护子树和- 强制在线异或处理
- 1
信息
- ID
- 6028
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者