1 条题解
-
0
题目大意
给定一棵包含 个城市的树,Fabijan 需要按顺序访问城市 。每条边有两种通行方式:
- 单次票:每次通过花费 欧元
- 多次票:一次性花费 欧元,可无限次使用
求完成整个旅程的最小总花费。
问题分析
关键观察
- 树结构:城市间构成一棵树,任意两点间有唯一简单路径
- 访问顺序:需要依次访问 ,共 段行程
- 票务决策:对于每条边,如果经过次数 ,则选择单次票,否则选择多次票
问题转化
核心问题转化为:
- 计算每条边在所有 段行程中被经过的总次数
- 根据经过次数为每条边选择最优票务方案
算法设计
方法一:LCA + 树上差分
核心思想:利用最近公共祖先和树上差分高效统计边经过次数。
步骤
-
预处理:
- 构建树的邻接表表示
- 预处理LCA(倍增法或Tarjan算法)
- 记录每个节点的深度和父节点信息
-
路径统计:
- 对于每段行程 ,计算路径
- 路径可分解为:
- 使用树上差分标记路径上的边
-
差分统计:
- 从叶子节点向根节点进行DFS
- 累加差分数组,得到每条边的实际经过次数
-
成本计算:
- 对于每条边 ,经过次数为
- 成本 =
- 累加所有边的成本得到总花费
复杂度分析
- LCA预处理:
- 路径处理:
- 差分统计:
- 总复杂度:
方法二:欧拉序 + 树状数组
核心思想:利用欧拉遍历序和树状数组统计边经过次数。
步骤
-
欧拉序预处理:
- 对树进行DFS,记录每个节点的入序和出序
- 建立欧拉序列
-
路径标记:
- 对于路径 ,在欧拉序上进行区间标记
- 使用树状数组维护标记信息
-
次数统计:
- 通过树状数组查询每条边的经过次数
- 同样使用贪心策略选择票务方案
方法三:重链剖分
核心思想:使用树链剖分高效处理路径操作。
步骤
-
树链剖分预处理:
- 进行重链剖分,建立线段树结构
- 记录每个节点所在重链信息
-
路径操作:
- 对于每段行程 ,在剖分后的链上进行区间加操作
- 使用线段树维护边经过次数
-
结果统计:
- 查询每条边的最终经过次数
- 计算最小总成本
实现细节
LCA实现(倍增法)
// 伪代码 void dfs(int u, int parent) { depth[u] = depth[parent] + 1; fa[u][0] = parent; for (int i = 1; i <= LOG; i++) { fa[u][i] = fa[fa[u][i-1]][i-1]; } for (auto &edge : adj[u]) { if (edge.v != parent) { dfs(edge.v, u); } } } int lca(int u, int v) { if (depth[u] < depth[v]) swap(u, v); for (int i = LOG; i >= 0; i--) { if (depth[fa[u][i]] >= depth[v]) { u = fa[u][i]; } } if (u == v) return u; for (int i = LOG; i >= 0; i--) { if (fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } } return fa[u][0]; }树上差分实现
// 伪代码 void mark_path(int u, int v) { int p = lca(u, v); diff[u]++; diff[v]++; diff[p] -= 2; } void dfs_count(int u, int parent) { for (auto &edge : adj[u]) { if (edge.v != parent) { dfs_count(edge.v, u); edge_count[edge.id] = diff[edge.v]; diff[u] += diff[edge.v]; } } }关键洞察
算法选择
- 推荐方法一:LCA + 树上差分,实现相对简单,效率高
- 适用于 的大规模数据
优化技巧
- 空间优化:使用邻接表存储树结构
- 时间优化:预处理LCA避免重复计算
- 常数优化:使用数组代替STL容器
边界情况
- 单次票更优:当 时选择单次票
- 多次票更优:当 时选择多次票
- 相等情况:根据题意 ,相等时选择单次票
复杂度对比
方法 预处理复杂度 查询复杂度 总复杂度 LCA+差分 欧拉序+树状数组 重链剖分 总结
本题的核心在于将复杂的旅程规划问题转化为树上的路径统计问题。通过LCA快速计算路径,利用树上差分高效统计边经过次数,最后使用贪心策略为每条边选择最优票务方案。这种"树结构 + LCA + 差分 + 贪心"的组合是解决此类问题的经典模式。
关键点:理解树上差分的原理,掌握LCA算法的实现,以及正确应用贪心决策策略。
- 1
信息
- ID
- 4287
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者