图论学习笔记

圆方树

这里的圆方树指广义圆方树。

对于一张 \(n\) 个点的无向图,其中包含 \(k\) 个点双,那么这张图建出的圆方树一共有 \(n+k\) 个点,其中前 \(n\) 个点为原图中的点,称为圆点,后 \(k\) 个点每个点代表一个点双,称为方点,每个点双与其中包含的点连边构成一个菊花,这 \(k\) 个菊花经由图中的割点连在一起。

圆方树的一些性质:

  • 任取树上的一条链,其中圆点与方点交替出现。
  • 两个圆点 \(u,v\) 在原图中简单路径的并等价于圆方树上 \(u,v\) 间的路径,且该路径上的圆点为 \(u,v\) 间路径的必经点。
  • 顺带一提,除了两个点由一条边相连的情况,一个点双一定是一个边双。

在圆方树中,我们经常通过给每个点赋上恰当点权的方式解决问题。

例题:

铁人两项

枚举起点和终点,那么问题变为求这两点间简单路径点集的并,这等价于求圆方树上两点间间路径代表的点的并。

建立圆方树,给圆点赋 \(-1\) 的权,方点赋其代表的点双大小的权,那么点对 \(u,v\) 的答案就是圆方树上 \(u,v\) 路径的权值和。

Proof:首先我们记录了路径上所有点双大小的和,但这样会算重,因为两个点双间由同一个割点相连,给圆点赋值为 \(-1\) 恰好消掉了多算的一次。

然后换一种统计方式,树形 dp 求经过点 \(x\) 的路径条数在乘上这个点的权即可,注意图可能不连通。

Tourists

这题 *3200

要求所有简单路径上的最小值,那么我们可以建立圆方树,圆点的权值为它自己,方点的权值为与它相连的圆点的权值的最小值,树剖加线段树维护即可。

但是这样做一个圆点的修改会影响到若干个方点,所以我们将方点的权值改为它所有子节点的权值的最小值,这样修改时只需要改父亲即可。

注意这样做如果两点间 LCA 为方点的话还要算上它的父亲。

为了方便的修改权值,我们可以对每个点开一个 multiset,得以快速维护。

战略游戏

首先答案为点集中任取两点组成的点对间路径上圆点的并集大小,这个由圆方树的性质可以直接得到,所以设圆点的权值为 \(1\),方点的权值为 \(0\),求树上两点间权值和即可,但不应考虑两个端点。

但是这样做复杂度过高,考虑优化,类似于蓝书上异象石一题,将答案转化为包含集合中所有点的最小联通块,最终再减去集合的大小即可。

因此我们将这些点按照在树上的时间戳排序,然后依次统计相邻两点间的路径权值和,这里我们认为第一个点与最后一个点也相邻,这样一个点会算上两次,最后除 \(2\) 即可,但是这样不能统计第一个点与最后一个点的 LCA,最后要判一下。

Edge Queries

题目中的性质没有用,将题目中的简单路径转化为圆方树上两点间的路径,然后圆点权值为 \(0\),方点的权值为它代表的点双内部的边数,因为一个点双中删一条边并不影响连通性。但要特判只有一条边的情况,此时不能删边。

如何统计点双中边的数量呢?我们可以对一个点双中的点先打上标记,然后枚举以这个点双中的点为起点的边,如果其终点也在这个点双中,那么经过这个点双的边数加一。但因为是无向图,所以最后的边数要除二。

网络流

网络流的常用手法:拆点,总贡献减去最小割,集合划分模型,最大权闭合子图。

最大权闭合子图

\(w_x>0\) 连边 \(S\to x\),权值为 \(w_x\);若 \(w_x<0\),连边 \(x \to T\),权值为 \(-w_x\)。对于原图中的边 \((u,v)\),连边 \(u \to v\),权值为 \(+\infty\)

答案是 \(\sum \max(w_i,0)-\) 最小割。

上下界网络流

上下界网络流的基本想法是:先把所有的边流量都达到下界,然后再用减去下界得到的普通网络去调整使得每个点满足流量守恒。

1.无源汇可行流

2.有源汇可行流

有源汇与无源汇的区别就是,给定的源点 \(S\) 和汇点 \(T\) 不需要满足流量守恒。因此,我们选择由 \(T\to S\) 连一条权值为 \(+\infty\) 的边然后按照无源汇可行流的方式求解。这样子,\(T\)\(S\) 的流量是 \(x\) 的话,就意味着

虚树

应用虚树的条件:做出贡献的点只有给出的关键点和它们的 LCA,其余的点可以视作相同处理。

虚树对树的压缩保留了给出点的相对结构,但是对边权还要做出分析。

构造:使用单调栈维护虚树上的一条链,它的 \(dfn\) 从栈底到栈顶单调递增,也可以理解为深度单调递增。

按照 \(dfn\) 从小到大加入点。求出当前点 \(x\) 与栈顶的 LCA,记为 \(p\)

  • \(p\) 为栈顶,那么直接插入 \(x\) 即可。

  • \(p\) 不为栈顶,那么这两条路径肯定不完全重合,不断弹出栈顶直到栈顶下面的节点的 \(dfn\) 小于等于 \(p\),假设这个点为 \(x'\)

    • \(dfn_{x'}=dfn_p\),这意味着 \(x'=p\),此时只需要将栈顶弹出并连边
    • \(dfn_{x'}<dfn_p\),那么我们要先将栈顶弹出再插入 \(p\)此时 \(p\) 为第一次插入,\(p\) 要和栈顶连边。形象的说,就是 \(p\) 插在了原来的栈顶和 \(x'\) 之间。

明显 \(x\) 为第一次插入,这些第一次插入的点的邻接表需要清空。

最后栈里面还剩了一条链,依次连边

一种更简洁的做法是:直接将点按照 \(dfn\) 排序后将相邻两个点的 LCA 连边。根为 \(dfn\) 最小的点。

P2495 [SDOI2011] 消耗战

dp 是 \(f_x\) 表示 \(x\) 子树内的点都不与 \(x\) 联通的最小代价。然后若一条边连接 \(y \in \operatorname{Son}(x)\)\(x\),代价为 \(z\),若 \(y\) 是关键点这条边必断,否则是 \(\min(f_y,z)\)

我们想要建出虚树,但是我们要知道一段压缩的路径上用了什么信息。

对于新树上的一条边,它所代表的原树的路径上没有关键点,我们可以从这条路径上任选一条边断掉,所以其权值应设为原路径上的最小值。

P4103 [HEOI2014] 大工程*

考虑一棵树怎么做,那么第三问是求直径,第二问是类似直径的求法那么求,第一问是统计边被计算的次数。

如果建出虚树,一条边对应着原树上的一条路径,这条路径总是被一起计算的,那么可以将新边的权值设为路径长度。

在虚树上 dp 的时候要注意直径端点必须为两个关键点,所以需要考虑一下 dp 的初值。

posted @ 2024-03-29 17:20  aCssen  阅读(39)  评论(1)    收藏  举报