1 条题解

  • 0
    @ 2025-12-11 0:39:11

    一、题意理解

    我们有 nn 个城市,mm铁路线(铁路线是链状的),每条铁路线依次经过若干城市,并给出相邻两个城市之间的行车时间。

    每条铁路线上的边是单向的。
    你从城市 11 出发,到达城市 nn,可以在同一个城市换乘不同线路。

    目标:

    1. 找到最少花费时间的路线。
    2. 在满足最少时间的前提下,使得路径上所有相邻两城市之间的行车时间的平方和尽可能大。

    注意:“相邻两个城市”指的是在换乘后的路径中相邻的两个城市(不是地理上相邻,而是你在旅行中连续经过的两个城市)。
    例如:在一条线路上坐几站,再换乘另一条线路,那么换乘点的前后两段行车时间会被分别计入平方和。


    二、模型转化

    1. 最短路图 DAG

    首先,我们要找到从 1 到 n 的所有最短路对应的路径。
    这些路径构成一个 最短路 DAG:只要边 uvu \to v 满足 dis[u]+w=dis[v]dis[u] + w = dis[v],则这条边在最短路 DAG 上。

    2. 关键:拆“颜色链”

    原题中“铁路线”在最短路径 DAG 中可能只被部分使用。
    如果我们把同一条铁路线上连续出现在最短路 DAG 中的边看作一个颜色块(称为 trans_color),那么在一条颜色块内部,我们不能换乘,只能一直坐下去。
    只有颜色块的分界点(即铁路线中某条边不在最短路 DAG 中)才会形成换乘机会,或者铁路线起点/终点也是一种边界。

    为什么这样做?
    因为对于同一条铁路线且连续在最短路上的一段,我们是连续乘坐的,这些边的行车时间在最终路径上也是连续的。
    对平方和来说,这一整段的时间之和是该段的时间长度,平方和是该段内每段小边的平方和累加。
    当我们在不同颜色块之间换乘时,两个颜色块的最后一小段时间 t1t_1 和第一小段时间 t2t_2 之间就会产生 t22t_2^2 的贡献。

    3. 目标函数

    假设我们得到了一条最短路径:

    $$1 = v_0 \xrightarrow{t_1} v_1 \xrightarrow{t_2} v_2 \cdots \xrightarrow{t_k} v_k = n $$

    每个 tit_i 是某条铁路线上的一小段的时间。
    我们要最大化:

    i=1kti2\sum_{i=1}^k t_i^2

    i=1kti\sum_{i=1}^k t_i 是固定的(等于最短时间 dis[n]dis[n])。

    但这并不是对整体求平方和,而是对相邻两个城市之间的每一小段时间求平方和。
    如果我们把同一颜色块的边合并在一起考虑,设一个颜色块内部的时间段为 T=ta+ta+1++tbT = t_a + t_{a+1} + \dots + t_b
    其平方和贡献为 j=abtj2\sum_{j=a}^b t_j^2
    对两个不同颜色块,在换乘时,它们的连接点的时间 tbt_btat_{a'} 在两个不同块中,它们的平方 tb2t_b^2ta2t_{a'}^2 分别属于各自块的贡献。

    为了统一,我们定义:对于一个颜色块 cc,它内部连续时间的平方和是固定的(因为时间固定的情况下,平方和只依赖于每小段时间,而最短路 DAG 中这些时间固定)。
    唯一要决定的是:我们在哪个城市换乘到该颜色块,以及从哪个城市离开该颜色块,这些决策会影响该颜色块的起始城市结束城市,从而影响路径的时间划分和平方和。


    四、代码实现框架

    你的代码分为三大模块:

    1. Dijkstra 模块(dij::solve

    • 用所有原始边建图跑 Dijkstra,得到 dis[1n]dis[1 \dots n]
    • 重新建图:只保留最短路 DAG 上的边(dis[u]+w==dis[v]dis[u]+w==dis[v])。
    • 同时给同一条铁路线上且连续在最短路 DAG 中的边分配相同的 trans_color。这样形成若干个颜色链。

    2. 拓扑排序(topo::solve

    • 在最短路 DAG 上拓扑排序,保证 DP 时无后效性。
    • 对于每个城市 uu,记录经过它的所有颜色链编号(color[u] 是它所在的所有颜色链的集合,去重后)。
    • 之所以一个城市可能在多个颜色链中,是因为不同的铁路线经过它。

    3. 李超线段树 DP(lichao::solve

    这里是最关键的部分:

    状态定义

    f[u]f[u]:从 11uu 走最短路,且在 uu 结束当前颜色块时的最大平方和。

    转移

    当我们到达 uu,且 uu 在某个颜色链 cc 上时,我们可能:

    • 从同一条颜色链 cc 的前一个城市 vv 直接过来(不换乘),此时 f[u]f[u] 可从 f[v]f[v] 加上 (dis[u]dis[v])2(dis[u]-dis[v])^2 转移。
    • uu换乘到颜色链 cc,此时需要找到上一个颜色链的结束点 vvvvuu 不同链),则从 f[v]f[v] 加上新颜色链的第一段时间的平方(这里第一段时间是 dis[u]dis[v]dis[u]-dis[v] 吗?注意 vvuu 必须有一条最短路 DAG 边,且 uu 是颜色链 cc 的起点)。

    但实际上,代码里采用了一种更统一的方法

    对于每个颜色链 cc,维护一个李超线段树(横坐标是 dis[x]dis[x],纵坐标是 f[x]f[x] 加上某些调整项),当我们到达 uu 时:

    • 查询该颜色链 cc 内所有可能的 vvdis[v]dis[v] 在横坐标轴上)的最大值 f[v]2dis[v]dis[u]+dis[u]2f[v] - 2\cdot dis[v] \cdot dis[u] + dis[u]^2 之类的东西。
    • 这个查询的形式是 f[v]+(dis[u]dis[v])2f[v] + (dis[u]-dis[v])^2 的最大值。

    展开:

    $$f[v] + (dis[u] - dis[v])^2 = f[v] + dis[u]^2 - 2\cdot dis[u]\cdot dis[v] + dis[v]^2 $$

    dis[u]dis[u] 看作 xx,那么对于每个 vv 有一条直线:

    y=(2dis[v])x+(f[v]+dis[v]2)y = (-2\cdot dis[v]) \cdot x + (f[v] + dis[v]^2)

    x=dis[u]x = dis[u] 处求最大值。

    所以,对于每个颜色链,我们维护一个李超线段树,里面插入了该链上所有点 vv 对应的直线。

    查询时,对于 uu 所在的颜色链 cc,查询在 x=dis[u]x=dis[u] 处的最大值 QQ,那么:

    f[u]=max{f[u],Q+dis[u]2}f[u] = \max\{ f[u], Q + dis[u]^2 \}

    因为 QQ 已经包含了 f[v]2dis[v]dis[u]+dis[v]2f[v] - 2\cdot dis[v]\cdot dis[u] + dis[v]^2 的最大值,再加上 dis[u]2dis[u]^2 就得到 f[v]+(dis[u]dis[v])2f[v] + (dis[u]-dis[v])^2 的最大值。

    插入新直线

    当我们求出 f[u]f[u] 后,对于 uu 所在的所有颜色链 cc,插入直线:

    k=2dis[u],b=f[u]+dis[u]2k = -2\cdot dis[u], \quad b = f[u] + dis[u]^2

    表示 uu 可以作为新的起点供后面的点查询。


    五、算法复杂度

    • Dijkstra:O(silogn)O(\sum s_i \log n)
    • 拓扑排序与建图:O(si)O(\sum s_i)
    • 李超线段树:每个点会在它所属的每个颜色链中查询一次、插入一次,每个点所属颜色链数很少(最多为经过它的铁路线条数),总复杂度 O(silogn)O(\sum s_i \log n)

    空间 O(si)O(\sum s_i)


    六、总结

    这道题的核心在于:

    1. 最短路 DAG 的建立与颜色链划分。
    2. 将平方和最大化转化为每个换乘点的平方贡献独立,用 DP 优化。
    3. 使用李超线段树在颜色链维度维护一次函数最大值,实现高效 DP 转移。

    最终结果:输出 dis[n]dis[n]f[n]f[n],其中 f[n]f[n] 是在 nn 结束的最短路的最大平方和。


    如果你需要,我可以进一步解释李超线段树在这里如何帮助优化转移,或者画出更具体的转移图。

    • 1

    信息

    ID
    6061
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者