1 条题解
-
0
题目理解
这是 BalkanOI 2018 Minmaxtree 问题的解决方案。题目要求给一棵树的边赋权值,满足若干条路径的最大值/最小值约束。
代码思路解析
1. 问题转化
将约束条件转化为对每条边的限制:
- 对于
M x y z:路径上的所有边权值 ≤ z,且至少一条边权值 = z - 对于
m x y z:路径上的所有边权值 ≥ z,且至少一条边权值 = z
2. 树上倍增预处理
vector fa(O + 1, vector(n + 1, 0)); // 倍增祖先 vector L(O + 1, vector(n + 1, -1)); // 边权下界 vector R(O + 1, vector(n + 1, int(1e9) + 1)); // 边权上界3. 约束传播
利用树上倍增将路径约束传播到每条边:
Rev(k, O, 0) if (dep[fa[k][x]] >= dep[y]) upt(k, x), x = fa[k][x];对于每个约束条件,在LCA路径上的节点记录约束信息。
4. 约束下推
将高层节点的约束下推到叶子:
Rev(i, O, 1) For(u, 1, n) { L[i - 1][u] = max(L[i - 1][u], L[i][u]); R[i - 1][u] = min(R[i - 1][u], R[i][u]); // 传递给父节点 }5. 图论建模
将问题转化为二分图匹配:
- 左部:约束条件(每个z值)
- 右部:树边
- 边表示:该约束可以分配给该边
For(i, 2, n) { int l = mp[L[0][i]], r = mp[R[0][i]]; if (!l && !r) ; else if (!l) add(r, r, i); else if (!r) add(l, l, i); else add(l, r, i); }6. 环分解与赋值
通过DFS寻找环并进行权值分配:
function<bool(int, int)> dfs1 = [&](int u, int pa) { vis[u] = -1; for (auto [v, _] : E[u]) if (v != pa) { if (vis[v] == -1) return rt = v, true; else if (dfs1(v, u)) return true; } return false; };关键技巧
1. 树上倍增
高效处理路径约束的传播
2. 约束传递
将路径约束转化为对单条边的上下界约束
3. 图论建模
将边权分配问题转化为二分图问题
4. 环处理
通过环分解解决约束冲突
5. 贪心分配
在保证约束的前提下最大化满足条件
复杂度分析
- 树上倍增:
O(n log n) - 约束传播:
O(m log n) - 图构建:
O(n) - 环分解:
O(n + m) - 总复杂度:
O((n + m) log n)
总结
这个解法是典型的树上问题+图论建模组合:
- 预处理:使用树上倍增处理路径约束
- 转化:将约束问题转化为图论问题
- 求解:通过环分解和DFS解决匹配问题
- 构造:输出满足所有约束的解
体现了竞赛中问题转化和算法组合的高级技巧,特别是将树上约束问题转化为图论匹配问题的思路很有启发性。
- 对于
- 1
信息
- ID
- 4167
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者