图论杂题1
如题。
归程
- NOI 2018 D1T1
给你一张 \(n\) 个点 \(m\) 条边的无向图,每条边有长度 \(l\),海拔 \(a\) 两个参数。
\(Q\) 次查询,每次给定一个起点 \(u\) 和当前水位线 \(p\),你可以从 \(u\) 开始驱车经过 \(a_i > p\) 的边 \(i\) 到任意一点,然后弃车步行到 \(1\) 号点。
求最小的步行距离。\(T\) 组数据,\(n \leq 2 \times 10^5,m \leq 2 \times 10^5,Q \leq 4 \times 10^5\),强制在线
关于 SPFA,它死了
预处理出每个点到 \(1\) 号点的最短步行距离,那么查询就变成了求当前起点 \(u\) 驱车能到达的所有点中到 \(1\) 号点的最短步行距离。
海拔的限制非常烦。我们发现如果一条边在水位线为 \(p\) 时被淹没了,那么对于任意的水位线 \(k \geq p\),这条边都处于被淹没的状态。
考虑去刻画这个东西。
我们可以对海拔这一维做 Kruskal 重构树,把边排序,按照海拔从高往低扫,每次合并两侧节点时,记录下新建的节点的海拔和,合并它的两个儿子到 \(1\) 号点的最短步行距离的信息。
查询的时候,往上跳到第一个海拔大于当前水位线 \(p\) 的点,那么这个点记录的信息就是从当前起点出发,驱车能到达的所有点的信息的并,直接返回记录的最短步行距离即可。
视 \(n,m,Q\) 同阶,复杂度 \(O(T \cdot n \log n)\)。
AC Submission
No Rest for the Wicked
- QOJ1878
- zr NOIP 模拟 T4
给你一张 \(n\) 个点 \(m\) 条边的无向图。
每个点有安全度 \(a_i\) ,安全要求 \(b_i\),和价值 \(c_i\),保证 \(b_i \geq a_i\)。
你不可以先后经过两个点 \(i,j\) 使得 \(a_i > b_j\)。
求在此限制下从每个点出发能访问到的点中,价值最大是多少。
\(1 \leq n,m \leq 2 \times 10^5, 1 \leq a_i,b_i,c_i \leq 10^9\)
考虑任意一条合法的路径,我们可以按照 \(a_i\) 的前缀 \(\max\) 分段,段与段之间存在单向边连接,段内是双向边。
系统地说,设 \(a_u < a_v\),我们考虑一条从 \(u\) 开始,到达 \(v\) 的合法路径,不难发现,对于这条路径上所有非 \(v\) 的点 \(k\),都需要满足 \(a_k \leq a_u \leq b_k\)。那么一个点 \(u\) 的答案就是它能到所有满足 \(a_k \leq a_u \leq b_k\) 的点 \(k\) 的 \(\max c_k\) (双向边) 和这些点中走一步到满足 \(b_v > b_u\) 的点 \(v\)(单向边) 的答案取 \(\max\)。
考虑去刻画这个东西。
我们可以对安全度这一维度做线段树分治,先递归右子树,再递归左子树,做一个类似拓扑排序的东西。在分治到安全度为 \(x\) 的点的过程中合并所有满足 \(a_k \leq x \leq b_k\) 的点 \(k\),即维护从 \(a_u=x\) 的点 \(u\) 出发走双向边能到达的所有点 \(k\) 的 \(\max c_k\)。而对于剩下单向边的处理,我们考虑在算出一个点 \(v\) 的答案后,用它的答案去更新与 \(v\) 相邻的所有满足 \(a_u \leq b_v\) 的点 \(u\)。
复杂度 \(O(n \log^2n)\)
AC Submission
货物运输
- zr 训练赛 T2
给你一张 \(n\) 个点 \(m\) 条边的带边权无向图。
当经过一条边 \((u,v,w)\) 时,若你之前经过一条边权为 \(x\) 的边,经过这条边的代价将会变为 \(\min(x,w)\)。
求从 \(1\) 号点到 \(n\) 号点的最小代价。
\(n \leq 500,m \leq 10^5\)
和上一题很像,路径可以边权分段,那么我们只关心一条路径上边权的前缀最小值。
具体的,考虑一条边 \((u,v,w)\),令 \(w\) 是当前路径的前缀最小值,则接下来一定有一段形如 \(u→v⇝p\) 的路径,路径上的每一条边的边权都是 \(w\)。
刻画相对而言是简单的,我们把路径从大往小排序后按序松弛。先用 \(floyd\) 处理出任意两点 \(u,v\) 间的最小边数,记为 \(to_{u,v}\)。松弛到边 \((u,v,w)\) 时,由于我们是按边权从大往小松弛的,所以 \(w\) 一定是是当前的一个前缀最小值,然后对于任意一点 \(x\),我们用 \(dis_u+(to_{v,x}+1) \times w\) 去更新 \(dis_x\)。若在 \(u⇝x\) 的路径中出现了边权小于 \(w\) 的边,那么当前答案也只会偏大,在松弛到路径上的对应边时依然能算出正确答案,故这样做是有正确性的。
复杂度 \(O(n^3+nm)\)。
但是好像直接跑魔改 dijkstra 就能过(雾
Propagating Edges
- Atcoder soundhound2018 summer final D
给定一个有 \(n\) 个顶点、\(0\) 条边的无向图。
接下来 \(Q\) 次询问:
- 给定 \(u,v\),如果 \(u\) 和 \(v\) 之间没有边,则在 \(u\) 和 \(v\) 之间添加一条边。
- 给定一个点 \(u\),对于所有顶点对 \(a, b\),如果 \(u, a, b\) 三者连通,且 \(a, b\) 之间没有边,则在 \(a, b\) 之间添加一条边。
- 给定 \(u, v\),如果 \(u\) 和 \(v\) 之间直接有边,则输出
Yes,否则输出No。\(n \leq 10^5,Q \leq 2 \times 10^5\)
发现题目中只有连边操作,没有删边操作。故若 \(u,v\) 在 \(t\) 操作时连通了,则 \(u,v\) 在接下来任意一时刻均连通。
考虑使用 kruskal 重构树来刻画这个东西。
把操作和询问按照时间离线。对 \(u\) 节点进行 \(2\) 操作时,我们给当前 \(u\) 所在重构树的根节点打一个时间戳。
建好树后,从上往下 dfs 一遍更新所有结点的时间戳。
这样做的话,若 \(u,v\) 之间的边是根据 \(2\) 操作更新的,那么它们的 lca 的时间戳一定小于当前询问的时间。
对于 \(1\) 操作构建的边,直接用 map 判断即可。
复杂度 \(O(n \log n)\),常数有点大。
AC Submission
Bonus:做到 \(O(n\alpha (n))\)。
简单的数据结构题
- hjj NOIP 模拟 T3
给你一颗 \(n\) 个点的树,有边权,点权。
\(q\) 次操作:
- 查询点 \(u\) 的权值
- 对于 \(u\) 子树内所有节点 \(v\),若 \(u\) 到 \(v\) 路径上所有边权都 \(\geq y\),则将点 \(u\) 的权值 \(+x\)。
\(n,q \leq 10^5\)
依然考虑把边按照边权从大往小排序,建出 kruskal 重构树。这样满足 \(u ⇝ v\) 上所有边权都 \(\geq y\) 的所有 \(v\) 都落在重构树上的一个子树内。
故对重构树求出 dfn 后,满足 \(u ⇝ v\) 上所有边权都 \(\geq y\) 的所有 \(v\) 在重构树上的 dfn 落在一个区间内。
而对于 \(v\) 在 \(u\) 子树内的限制,可以刻画为 \(v\) 在原树上的 dfn 落在 \([dfn_u,dfn_u+siz_u-1]\) 内。
问题转化为二维平面上的矩形加,单点求和。使用你喜欢的方式维护即可。
本题还有树分块,树上分治等做法,但是较繁。

浙公网安备 33010602011771号