20ZR暑期联赛班——图论
欧拉回路
P1341 无序字母对
给定 n n n 个各不相同的无序字母对。请构造一个字典序最小的有 ( n + 1 ) (n+1) (n+1) 个字母的字符串使得每个字母对都在这个字符串中出现。
给定的字母对两个字母必须连续出现,而且只出现一次。所以考虑将构成无序对的两个字母连无向边,如果构成的图是欧拉图,那么有解跑欧拉回路即可。因为要求字典序最小,所以每次先遍历小点再遍历大点,可以用一个堆维护。
CF547D Mike and Fish
给定平面上的 n n n 个点的坐标,你需要将每一个点进行红蓝染色,满足任意一行一列红蓝点的数量之差最多为 1 1 1。 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^{5} 1≤n≤2×105
先对坐标离散化。对于一个点 ( x , y ) (x,y) (x,y) 我们连一条 x x x 到 n + y n + y n+y 的边,那么问题转换成了给边定向,让每个点的入度和出度之差不超过一。分类一下,度数相同的在无向图上就是每个点的度数为偶数。度数差为一的在无向图上每个点的度数为奇数,那么再把这些奇数点连到虚拟点上,那么度数就是偶数了,再考虑虚拟点,因为奇数点个数一定为偶数,跑欧拉回路即可。
还有二分图染色的方法。将横纵坐标相同的点两两连边,构成了二分图,剩下的点最多一个不用管。然后进行二分图染色即可。女少口阿。
P4568 飞行路线
给定一张 n n n 个点 m m m 条边的带权无向图,你可以把至多 k k k 条边的边权变成 0 0 0,求从 s s s 到 t t t 的最短路。 2 ≤ n ≤ 1 0 4 , 1 ≤ m ≤ 5 × 1 0 4 , 0 ≤ k ≤ 10 2 \leq n \leq 10^{4}, 1 \leq m \leq 5 \times 10^{4}, 0 \leq k \leq 10 2≤n≤104,1≤m≤5×104,0≤k≤10。
分层图。设 d i , j d_{i,j} di,j 为到 i i i 点用了 j j j 次的最短路。
P2761 软件补丁问题
有一款软件有
n
n
n 个 BUG,还有
m
m
m 个补丁。 对于每一个补丁,都有两个 BUG 集合
B
1
,
B
2
,
B_{1}, B_{2},
B1,B2, 表示只有当 这个软件包含了
B
1
B_1
B1 中的所有 BUG 而不包含
B
2
B_2
B2 中的任意一个 BUG 的时候,这个补丁才能使用。
对于每一个补丁,它会修复一个 BUG 集合
F
1
,
F_{1},
F1, 同时引人 另一个 BUG 集合
F
2
,
F_{2},
F2, 运行需要
t
t
t 的时间。 求将所有 BUG 都修复需要的最短时间,无法修复输出
−
1
-1
−1。
1 ≤ n ≤ 20 , 1 ≤ m ≤ 100 1 \leq n \leq 20,1 \leq m \leq 100 1≤n≤20,1≤m≤100
将 BUG 状压,把一个状压的状态看成一个点,如果通过一个补丁能从一个点到另一个点,那么就连边,边权为时间。跑 Dijkstra 即可。
生成树 瓶颈树 最短路树
最小生成树即为最小瓶颈树,最大生成树即为最大瓶颈树。
void Kruskal() {
int ans = 0;
for (int i = 1; i <= n; i++) f[i] = i;
sort(e + 1, e + tot + 1, cmp);
int cnt = 0;
for (int i = 1; i <= m; i++) {
int x = e[i].x, y = e[i].y, z = e[i].z;
int ux = find(x), uy = find(y);
if (ux != uy) {
ans += z; f[ux] = uy;
if (++cnt == n - 1) break;
}
}
}
如果将一个点到其余所有点的最短路径保留,其它的删掉,那么构成了一棵树,这棵树叫最短路径树。
P1967 货车运输
一张 n n n 个点 m m m 条边的图,每一条边有一个限重。 现在有 q q q 组询问,每次问你从 u u u 到 v v v,在不超过限重的情况下,重量最大可以是多少。 n ≤ 1 0 4 , m ≤ 5 × 1 0 4 , q ≤ 3 × 1 0 4 n \leq 10^{4}, m \leq 5 \times 10^{4}, q \leq 3 \times 10^{4} n≤104,m≤5×104,q≤3×104
解法还是很多的,这里可以发现要让最小值尽可能大,所以建立一棵最大生成树。把路径用 lca 转一下即可。
P3953 逛公园
给你一张 n n n 个点 m m m 条边的有向图,问你从 1 1 1 到 n n n 与最短路的差不超过 k k k 的路径有多少条。 可能有 0 0 0 边,如果数量无限输出 − 1 -1 −1。路径可以重复经过一个点。
n ≤ 100000 , m ≤ 200000 , k ≤ 50 n \leq 100000, m \leq 200000, k \leq 50 n≤100000,m≤200000,k≤50。
可以发现,合法路径有无限个当且仅当有一个全为 0 0 0 的环中的一个点在最短路的路径上。先正反建边跑一下 dijkstra,令 d 1 d_1 d1 为 1 1 1 的单源最短路, d 2 d_2 d2 为 n n n 的单源最短路。对于一条边 ( u , v ) (u,v) (u,v),如果有 d ( u ) + d ( v ) = d n d(u) + d(v) = d_n d(u)+d(v)=dn,这意味着 w ( u , v ) = 0 w(u,v) = 0 w(u,v)=0,那么把这条边加入新的图中。再拓扑排序判断有没有环,搞定了 − 1 -1 −1。
k k k 小,那么就分层图了。设 f i , j f_{i,j} fi,j 为从 1 1 1 到 i i i,与最短路差为 j j j 的路径有多少条。用类似最短路松弛的方式计数转移即可。
CF1163F Indecisive Taxi Fee
3k 难度的神仙题,能学到不少套路。
给你一张 n n n 个点 m m m 条边的图,有 q q q 次询问,每次问你如果更改一条边的边权,从 1 1 1 到 n n n 的最短路是多少。
容易想到正反建边,预处理处理从 1 1 1 和从 n n n 走的最短路径,分别为 d 1 d_1 d1 和 d 2 d_2 d2。分类讨论一下,令改的是 ( a , b ) (a,b) (a,b) 这条边
- 改的边不在最短路上,且改大了。不用管。
- 改的边不在最短路上,且改小了。拿 d 1 ( a ) + d 2 ( b ) + w ( a , b ) d_1(a) + d_2(b) + w(a,b) d1(a)+d2(b)+w(a,b) 与原来的最短路取最小值。
- 改的边在最短路上,且改大了。新的最短路有可能绕过被修改的边,好像不好搞先一放。
- 改的边在最短路上,且改小了。在最短路的基础上减一下即可。
考虑第三类。如果把改的边删掉,求不经过这条边的最短路,与原来的最短路加改边产生的贡献取最小值即可。而且求不经过某条边的最短路会有多次询问。

先考虑经过一个点的最短路,可以删最短路上点的范围。
令最短路为 E 1 ∼ E k E_1 \sim E_k E1∼Ek,枚举一条边 ( u , v ) (u,v) (u,v)。经过 ( u , v ) (u,v) (u,v) 的最短路径也会经过 E 1 ∼ E x E_1 \sim E_x E1∼Ex 和 E y ∼ n E_y \sim _n Ey∼n,相当于最短路的前缀和后缀或为空。那么考虑求 x x x 和 y y y,可以在前面的第一次 Dijkstra 中,记录最短路的路径,在正反两向的 Dijkstra 分别求出每个点的 x x x 和 y y y。如果能松弛,看看点在不在最短路径上,不在的话就继承父亲的 x x x 或 y y y,正确性显然。因为最短路先松弛下标小的点,所以不用担心有另一个最短路的范围比我们求的大。

再考虑经过一条边允许删的点的范围,考虑边的两个点 u , v u,v u,v 可能会有多个情况,所以范围是 u x + 1 ∼ v y − 1 u_x + 1 \sim v_y - 1 ux+1∼vy−1 和 v x + 1 ∼ u y − 1 v_x + 1 \sim u_y - 1 vx+1∼uy−1。那么维护一棵 1 ∼ k 1 \sim k 1∼k 的线段树,将这两段用 d 1 ( u ) + d 2 ( v ) d_1(u)+d_2(v) d1(u)+d2(v) 更新最小值即可。查询时,找不包括给定边的两个点的所有区间的最小值。
细节多,时间复杂度 O ( ( m + q ) log n ) O((m+q) \log n) O((m+q)logn)。确认了码量,是我调不出的题 /kk。
P1351 联合权值
无向连通图 G G G 有 n n n 个点, n − 1 n-1 n−1 条边。点从 1 1 1 到 n n n 依次编号,编号为 i i i 的点的权值为 W i , W_{i}, Wi, 每条边的长度均为 1 1 1。图上两点 ( u , v ) (u, v) (u,v) 的距离定义为 u u u 点到 v v v 点的最短距离。对于图 G G G 上的点对 ( u , v ) , (u, v), (u,v), 若它们的距离为 2 2 2 则它们之间会产生 W u × W v W_{u} \times W_{v} Wu×Wv 的联合权值。请问图 G G G 上所有可产生联合权值的有序点对中,联合权值最大的是多少? 所有联合权值之和是多少? 1 ≤ n ≤ 200000 1 \leq n \leq 200000 1≤n≤200000
枚举点对一定是不行的,有一个直接的思路是枚举 ( u , v ) (u,v) (u,v) 中的一个,再去找另一个,可以通过,但造数据的不知道菊花图这东西。
那么可以树形 dp,这个和枚举中转点是相似的。考虑 x x x 的儿子 y 1 ∼ y k y_1 \sim y_k y1∼yk 能找到那些点对。简单的是 y 1 ∼ y k y_1 \sim y_k y1∼yk 与 x x x 的父亲组合,也可以从 y 1 ∼ y k y_1 \sim y_k y1∼yk 中随意选两个。但直接做的话还会倒在菊花图下。
考虑 k = 2 k=2 k=2 时 y 1 × y 2 = ( y 1 + y 2 ) 2 − ( y 1 2 + y 2 2 ) 2 y_1 \times y_2 = \frac{{(y_1 + y_2)}^2 - ({y_1}^2+{y_2}^2)}{2} y1×y2=2(y1+y2)2−(y12+y22)。推下去发现 y 1 ∼ y k y_1 \sim y_k y1∼yk 的两两组合贡献为 ( ∑ 1 k y i ) 2 − ∑ 1 k y i 2 (\sum_{1}^k y_i)^2 - \sum_{1}^k y_i^2 (∑1kyi)2−∑1kyi2。至此可以通过了。
P1983 车站分级
有 n n n 个火车站, m m m 批合法的车次的运行情况。每批车次的运行情况给定了始发站,终点站,途中停靠的车站。请你给每个车站分级,满足要求:如果一趟车停靠的火车站级别为 x x x,那么始发站终点站之间(包括)级别 ≥ x \ge x ≥x 的车站都要停靠。在该条件下,回答火车站至少分成几个级别。
对于给定的 m m m 批车次,先建一个有向图,边的关系即题中的偏序关系,即为将有车停靠的站点连向所有没有车停靠的站点。如果有一条有向边 ( u , v ) (u,v) (u,v) 那么 u u u 必须在 v v v 的前面,这不就是拓扑排序吗?所以一些比较复杂的偏序问题,可以转换到 DAG 上进行拓扑排序 + dp 试一试。
PS,暴力建图复杂度是 O ( n 2 m ) O(n^2m) O(n2m) 的,需要信仰。考虑建立一个虚拟的中转点来优化建图,复杂度为 O ( n m ) O(nm) O(nm)。
P4643 阿狸和桃子的游戏
Easy = NOI \text{Easy} = \text{NOI} Easy=NOI
有一张 n n n 个点 m m m 条边的图,有点权和边权。先手后手轮流染黑白两色,最后的得分是自己染的点权和 + + + 两端均为自己的颜色的边权和,双方采用最优策略,求先手的分数减去后手的分数。
不要想歪,这不可能是正儿八经的博弈论,这是联赛啊。先提一下,遇到点权和边权同时存在的题,尤其是其中一个的定义有点与众不同时,考虑能不能把点权和边权转化为一个东西,常为边权转点权。
如果一条边的两个端点同色,那么会给这两个点贡献,先让它平分给两个点。如果两个端点异色,那么两个点都没有贡献,发现平分的话抵消了。所以先把边权平分给点权,带个分数可以同时 × 2 \times 2 ×2。
那么将点权拍个序,从大到小交替贪心选即可。女少口啊。
P2680 运输计划
一株 n n n 个点的树,给你 m m m 条路径。 你需要选出一条边把边权改成 0 0 0,让这些路径长度的最大值最小。
二话不说,看到最大值最小先考虑二分。有的边已经满足条件了,不去管。那么要让其余的路径都减小到二分值及其以下,那么改的边要被其余的路径经过。假设有 k k k 条路径超限制,那么把路径上的每个边的计数器累加,最后计数器为 k k k 的取个最值。给定的是树,树上差分即可。
卡常差评。
CF1349C Orac and Game of Life
给定第 0 0 0 时刻的 n × m n \times m n×m 的 01 01 01 矩阵。 每过一个时刻, 01 01 01 矩阵都会发生如下的变化:对于 x x x 行第 y y y 列的格子。若其上下左右四个方向中相邻的格子存在与其数字相同的格子,则此格子的数字在下一个时刻会取反。
有 t t t 次询问。每次问你在第 p p p 个时刻第 x x x 行第 y y y 列的格子上的数字是什么。
感觉一下,发现不断变化的位置的范围是在扩大的,而且扩大到一定程度就停下了。这样有点抽象,就拿良心的样例三试一试。
0 1 0 1 1
1 0 1 1 0
0 1 1 0 1
1 1 0 1 0
1 0 1 0 1
用 0 0 0 表示不会变化, 1 1 1 表示在不断变化。那么范围随单位时间的扩大如下
0 0 0 1 1
0 0 1 1 0
0 1 1 0 0
1 1 0 0 0
1 0 0 0 0
0 0 1 1 1
0 1 1 1 1
1 1 1 1 0
1 1 1 0 0
1 1 0 0 0
可以大胆猜测,每次 1 1 1 都会向四个方向扩展一次。所以一个 bfs 搞定。女少口β可。
CF209C Trails and Glades
给一张图,添加最少的边使得整张图存在一条 1 1 1 为起始和结束点的欧拉回路。 1 ≤ n ≤ 1 0 6 , 0 ≤ m ≤ 1 0 6 1 \leq n \leq 10^{6}, 0 \leq m \leq 10^{6} 1≤n≤106,0≤m≤106
遇到这类有多个连通块的,往往先考虑连通块内部的贡献,再考虑连通块间的贡献。
从欧拉回路的定义入手,对于一个连通块,将度数为奇数的点两两配对,可能剩下一个。所以先去考虑连通块的连接,优先把度数为奇数的点连起来,那么其余的奇点两两配对。最多剩下一个,这个点要连出两条边。
CF1311E Construct the Binary Tree
给定 n n n 和 d d d,你需要构造一株 n n n 个点的二叉树,满足所有点的深度之和恰好为 d d d。
先考虑深度最小的完全二叉树,如果 d d d 比这个深度小那么直接不可能。否则对深度进行修改,找一个叶子节点到根的链,不断把深度最大的点挂在这条链的下面。还要输出方案,啊这。
P1979 华容道
给定一个 n × m n \times m n×m 的棋盘,只有一个空的位置。剩下的有的是障碍,有的是可移动的棋子。给定一个棋子的初始位置和目标位置,求让这个棋子移动到目标位置至少要移动几次棋子,或者回答不可能。 1 ≤ n , m ≤ 30 , 1 ≤ q ≤ 500 1 \leq n, m \leq 30,1 \leq q \leq 500 1≤n,m≤30,1≤q≤500
吐槽,这道题和图论关系不大啊。
数据范围这么小,先想爆搜,但棋子和空格可以一起走很烦。干脆 dp,设 f i , j , x , y f_{i,j,x,y} fi,j,x,y 为棋子在 ( i , j ) (i,j) (i,j),空格在 ( x , y ) (x,y) (x,y) 的最少移动次数,枚举空格从哪移动过来的,如果空格与棋子相邻,还可以转移棋子。但是 O ( q m 2 n 2 ) O(qm^2n^2) O(qm2n2) 会超时。
考虑空格与棋子相邻才有用,那么设 f i , j , k f_{i,j,k} fi,j,k 为棋子在 ( i , j ) (i,j) (i,j),空格在 ( i , j ) (i,j) (i,j) 的上下左右的最少移动次数。不过这样可能没有初始状态,所以要用 bfs 预处理空格到棋子的上下左右要移动多少次即可。
CF875F Royal Questions
有 n n n 个王子 m m m 个公主,每一个公主喜欢其中两个王子,还有一个美丽度。 你需要将王子和公主配对,使得每一个公主都和自己喜欢的王子配对,并且配对的公主美丽度之和最大。
n , m ≤ 200000 n,m \leq 200000 n,m≤200000
带权二分图匹配板子!哦数据范围 2e5 那没事了。
可以发现有一个公主喜欢两个王子的条件,如果构图的话,每个连通块都是树或基环树。这其实是个模板,但是联赛基础不知道 /xk。先试一试对每个连通块讨论,好像行不通,那就从零开始加边吧。
加边前先按美丽度降序排序,对于边 ( u , v ) (u,v) (u,v),两个端点 u u u 和 v v v 可能在一个连通块中也可能不在,可能在树上也可能在基环树上,那分类讨论,要维持一棵基环树的点数一直等于边数。
- 不连通,在两棵树中:加入这条边,得到一棵新的树。
- 不连通,在一棵树和一棵基环树中:加入这条边,得到一棵基环树。
- 不连通,在两棵基环树中:无法加入。
- 连通,在一棵树中:加入这条边,树变成基环树。
- 连通,在一棵基环树中:无法加入。
是不是和生成树有点像?这个模板就叫最大生成基环树,所以用并查集维护,多加一个 bool 数组来表示是不是基环树即可。

浙公网安备 33010602011771号