1 条题解
-
0
题解
问题分析
这是一个图论 + 区间覆盖 + 最优化问题。我们需要判断每个游客是否可以通过交换通票(花费一定手续费)来获得能够从车站 到达所有车站的通行权限。
关键观察
- 可达性条件:通票 能够到达所有车站,当且仅当包含的路线能够形成从 到所有车站的路径
- 双指针思想:对于固定的左端点 ,找到最小的 使得通票 满足条件(记为 )
- 对称性:对于固定的右端点 ,找到最大的 使得通票 满足条件(记为 )
算法思路
离散化 + 双指针 + 线段树优化:
离散化处理
- 将所有公司编号和查询的 一起离散化,减少值域
双指针预处理
- :对于离散化后的左端点 ,最小的右端点使得通票 能到达所有车站
- :对于离散化后的右端点 ,最大的左端点使得通票 能到达所有车站
线段树维护
- 用线段树维护对于每个左端点 ,满足条件的最小花费:
- 支持区间最小值查询和单点修改
核心数据结构
双指针扫描
for(int i=1, j=1; i<=lsc; ++i) { while(j<=lsc && cnt<n) { for(auto z:vc[j]) { // 添加公司j的所有路线 cnt += !ct[z]; ct[z]++; } g[j] = i-1; j++; } if(cnt < n) break; f[i] = j-1; // 移除公司i的路线 for(auto z:vc[i]) { ct[z]--; cnt -= !ct[z]; } E[j-1].push_back(i); }线段树查询
// 查询区间[1,l]的最小花费 ans[id] = Ask(1, 1, lsc, 1, l); // 考虑对称情况 if(g[i]) ans[id] = min(ans[id], (ll)ls[i] - ls[g[i]]);算法步骤
- 离散化:将所有公司编号和查询端点映射到
- 预处理:按公司编号分组存储路线终点
- 双指针扫描:计算 和
- 线段树处理查询:
- 按右端点排序查询
- 维护当前可用的左端点花费
- 回答每个查询的最小交换花费
- 判断答案:比较最小花费与可用现金
复杂度分析
- 离散化:
- 双指针:,每个路线被加入/移除一次
- 线段树: 处理所有查询
- 总复杂度:
判断逻辑
对于查询 :
- 如果原通票就满足条件:直接输出
Yes - 否则检查最小交换花费是否 :
- 花费 =
- 其中 是离散化后的位置
算法标签
- 离散化
- 双指针
- 线段树
- 图的可达性
- 区间覆盖
- 最优化问题
- 1
信息
- ID
- 3970
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者