1 条题解
-
0
问题分析
我们需要维护一棵有根树,支持三种操作:
- 路径重染色:将某个节点到根的路径染成全新颜色
- 路径查询:查询两点路径上不同颜色的数量
- 子树查询:查询子树中到根路径颜色数的最大值
核心算法
算法框架:LCT + 树链剖分 + 线段树
使用LCT(Link-Cut Tree)维护树的链结构,结合DFS序和线段树来支持子树查询。
关键数据结构
- LCT节点:维护splay树结构,记录子树大小和顶部节点
- 线段树:维护每个DFS序位置的权值(颜色数)
- 倍增数组:用于LCA查询
算法步骤详解
1. 初始化处理
void dfs(int x) { dfn[x] = ++cnt; // DFS序 siz[x] = 1; // 子树大小 // 预处理倍增数组 for (int i = 1; i <= 17; i++) f[x][i] = f[f[x][i-1]][i-1]; // 递归处理子树 for (int y : e[x]) { if (y == fa[x]) continue; fa[y] = f[y][0] = x; dep[y] = dep[x] + 1; dfs(y); siz[x] += siz[y]; } // 初始化线段树权值 update(1, 1, n, dfn[x], dfn[x] + siz[x] - 1, 1); }2. 路径重染色操作
void access(int x) { for (int y = 0; x; y = x, x = fa[x]) { splay(x); int z = t[rs].top; update(1, 1, n, dfn[z], dfn[z] + siz[z] - 1, 1); // 移除旧链 z = t[y].top; update(1, 1, n, dfn[z], dfn[z] + siz[z] - 1, -1); // 添加新链 rs = y; pushup(x); } }access(x)操作将x到根的路径变为偏爱边,相当于重染色。3. 路径查询操作
int lca = get(x, y); cout << query(x) + query(y) - query(lca) * 2 + 1 << '\n';利用公式:
路径颜色数 = query(x) + query(y) - 2*query(lca) + 14. 子树查询操作
query(1, 1, n, dfn[x], dfn[x] + siz[x] - 1)直接在DFS序对应的区间查询最大值。
算法标签
- Link-Cut Tree (LCT)
- 树链剖分 (Heavy-Light Decomposition)
- 线段树 (Segment Tree)
- 最近公共祖先 (LCA)
- DFS序 (Euler Tour)
复杂度分析
- 预处理:
- access操作:均摊
- 路径查询:
- 子树查询:
- 总复杂度:
关键技巧
1. 权值维护原理
每个节点存储的是从该节点到根的路径上的颜色数。当进行access操作时,实际上是在调整偏爱路径,对应颜色数的变化。
2. LCT与线段树的结合
// access时更新线段树 update(1, 1, n, dfn[z], dfn[z] + siz[z] - 1, 1); // 断开旧链 update(1, 1, n, dfn[z], dfn[z] + siz[z] - 1, -1); // 连接新链通过DFS序将LCT的子树操作映射到线段树的区间操作。
3. 路径查询公式推导
对于路径x-y:
query(x):x到根的颜色数query(y):y到根的颜色数query(lca):lca到根的颜色数- 路径颜色数 =
query(x) + query(y) - 2*query(lca) + 1
4. 懒标记线段树
void lazy(int x, int v) { tr[x].maxn += v; tr[x].tag += v; }支持区间加和区间最大值查询。
样例验证
对于样例操作序列:
- 初始查询
2 4 5:路径4-3-5,3种颜色 → 输出3 - 查询
3 3:子树中到根路径最大值 → 输出4 - 重染色
1 4:更新路径1-2-3-4 - 查询
2 4 5:路径颜色减少 → 输出2 - 重染色
1 5:更新路径1-2-3-5 - 查询
2 4 5:路径颜色保持 → 输出2
正确性证明
-
access操作正确性:LCT的access操作确保每次重染色只影响一条链。
-
颜色数维护:线段树正确维护每个节点到根的路径颜色数。
-
路径查询:利用树的性质和LCA正确计算路径颜色数。
该解法通过LCT动态维护树链结构,结合线段树高效处理子树查询,实现了所有操作的对数时间复杂度。
- 1
信息
- ID
- 4049
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者