20241015 最短路与生成树

20241015 最短路与生成树

@. The army of Thutmose III

题号是 @,原因是过了之后才发现测不了被删了。

注意到问题形如最大值最小,直接上二分答案。考虑如何 check。设当前 check 的答案为 \(x\)

容易获得一个猜想,点一定放在区间端点上。那么将区间端点离散化。记 \(a_i\) 表示第 \(i\) 个位置放了 \(0/1\) 个点。

\(a\) 作前缀和获得 \(s\),那么分析 \(s\) 具有什么性质。容易发现:

\[\begin{cases} s_i\ge 0&\\ 0\le s_i-s_{i-1}\le 1&\\ \forall 1\le l_i,r_i,s_{r_i}-s_{l_i-1}\le x \end{cases} \]

容易发现这些性质符合差分约束的形式,直接 spfa 判断,最后对求出的 \(s\) 作一遍差分就能知道在哪些位置放点。

A. 矩阵游戏

容易发现,只要确定了某一行和某一列就能推出整个矩阵。不妨设第 \(n\) 行和第 \(m\) 列为 \(0\),推出一个初始的 \(a\)

但是题目要求 \(0\le a_{i,j}\le 10^6\),那么直接这么构造可能会超出这个范围,那么考虑对 \(a\) 进行一些什么样的操作可以使得 \(b\) 不变。可以看出,对于某一行,我们让奇数位的数字同时加上一个 \(x\),偶数位的数字同时减去 \(x\),这样得到的 \(b\) 矩阵就与原来相同,列同理。那么我们设对第 \(i\) 行进行了 \(x=r_i\) 的操作,第 \(j\) 列进行了 \(x=c_j\) 的操作,操作后的矩阵就是:

\[\begin{bmatrix} a_{1,1}+r_1+c_1 & a_{1,2}-r_1+c_2 & a_{1,3}+r_1+c_3 & \dots &\\ a_{2,1}+r_2-c_1 & a_{2,2}-r_2-c_2 & a_{2,3}+r_2-c_3 & \dots &\\ a_{3,1}+r_3+c_1 & a_{3,2}-r_3+c_2 & a_{3,3}+r_3+c_3 & \dots &\\ \dots & \dots & \dots & \dots \end{bmatrix} \]

这个形式看上去很接近差分约束,但还需要转化。将奇数行的 \(r_i\) 取相反数,偶数列的 \(c_j\) 取相反数,得到:

\[\begin{bmatrix} a_{1,1}-r_1+c_1 & a_{1,2}+r_1-c_2 & a_{1,3}-r_1+c_3 & \dots &\\ a_{2,1}+r_2-c_1 & a_{2,2}-r_2+c_2 & a_{2,3}+r_2-c_3 & \dots &\\ a_{3,1}-r_3+c_1 & a_{3,2}+r_3-c_2 & a_{3,3}-r_3+c_3 & \dots &\\ \dots & \dots & \dots & \dots \end{bmatrix} \]

这个形式就很漂亮了,可以使用差分约束。因为 \(0\le a_{i,j}+\Delta_{i,j}\le 10^6\),所以 \(-a_{i,j}\le \Delta_{i,j}\le 10^6-a_{i,j}\)。根据这个不等式直接差分约束即可求出合法的 \(r_i\)\(c_j\)

I. Dynamic Shortest Path

注意到时限有 \(10\) 秒,而 \(q\) 只有 \(2000\),增加边权时即使暴力加也只有 \(10^6\) 的运算量,所以我们可以考虑暴力一点的想法。有一个显然的做法:每次加完边权后直接跑一遍 dijkstra 求出新的最短路,这样是 \(O(qm\log n)\) 的。

这样做常数大一点就过不去了,那么考虑这题有什么特殊的性质。可以发现,如果我们能做到在更新边权后在 \(O(n)\) 时间内更新最短路,复杂度就变成 \(O(qn)\),可以通过。注意到这题每次增加边权时都只增加 \(1\),那么每次从 \(1\) 到某个点的最短路变化量一定不会超过 \(c\)(即变化边权的边的数量)。于是考虑求解最短路的增量。

使用 Johnson 算法的思想,将每条边重新赋权为 \(w_{u,v}+dis_u-dis_v\),其中 \(dis\) 为原本的最短路。

这样,一条路径上所有边的权值和就为 \((\sum w)+dis_s-dis_t\)。当起点 \(s=1\) 时,\(dis_s=0\),那么路径的权值就为 \((\sum w)-dis_t\),也就是新的最短路减去原本的最短路,即最短路的增量。

因为增量的值域不大,所以我们可以用若干个值域上的队列来实现优先队列的功能。具体地说,对每个最短路的值开一个队列,队列中存放最短路增量为这个值的点。枚举小值域向大值域转移即可求出增量并更新最短路,单次时间复杂度 \(O(n+m+c)\)。这题有些卡常,慎用 long long,开 O2、Ofast 即可通过。

K. Kuroni and Antihype

将每个人看作一个点,那么最后就是求一个最大的生成森林。考虑转化成生成树。建立一个权值为 \(0\)\(0\) 号节点,第一种操作就相当于把点与这个点连边。以 \(0\) 为根,现在每条边的权值为深度较浅的点的点权,考虑将最终的答案先加上所有点的点权和,最后在减去点权和,那么由于除了 \(0\) 以外的所有节点均有且仅有一条父边,我们可以考虑将这个点的权值加到这条边上,那么每条边的权值就变成它连接的两个节点的权值和。

经过一系列转化,问题变成:两点之间有边当且仅当 \(a_u\&a_v=0\),边权为 \(a_u+a_v\),求最大生成树。

执行类似 kruskal 算法的过程。注意到边权的值域只有 \(4\times10^5\),那么考虑从大到小枚举边权并考虑连边。注意到当 \(a_u\&a_v=0\) 时,\(a_u+a_v=a_u|a_v\),说明在二进制下 \(a_u,a_v\) 都是边权的子集。根据这个性质,直接枚举边权在二进制下的子集。如果存在这样的点,就应该连边了。对于一种权值的所有点,记录它们是否已被连接到同一连通块中即可。具体可以画图加深理解。时间复杂度 \(O(3^{18}\alpha(n))\)

posted @ 2024-11-08 15:36  陆羽扬  阅读(0)  评论(0编辑  收藏  举报