费用流/凸性相关

Task 1

数轴上 \(n\) 个老鼠,\(m\) 个洞。每个老鼠要找一个洞回去,代价为距离(\(|x_1-x_2|\))。求最小代价和。

把老鼠和洞排序之后建出网络,大概是这样。
image
考虑费用流增广的过程。按照坐标从小到大加入点。

  • 加进来老鼠:按照增广的思路,我可以在左右两边的洞中,选一个距离较小的进去。
  • 加进来洞:这时候有神之一手。反向边会在什么时候影响增广?
    当且仅当形如这样:image
    就是前一个老鼠向右走了,但是这个老鼠可以吃一个负贡献,使得向左走更优。
    这个时候的反向弧,终点只会在某个洞的位置。所以我们扫到洞 \(p\) 的时候,如果有反向弧指向她,那么考虑她左边的空洞。
    设这条反向弧的边权为 \(-w\),流量为 \(f\),那么效果等价于把 \(p\) 左边的空洞中,最右边的 \(f\) 个的坐标向右移动 \(2w\)

那用线段树应该不难实现。考虑两棵线段树,一棵用于维护反向弧的区间加标记,一棵用于查找左边最近的空洞,也需要实现区间加。
但是陈江伦老师说除了排序可以线性?不懂。

然后似乎有一个更好写的做法。
仍然按照坐标从小到大考虑。但是这次对于反悔弧,我们在加入一个洞的时候考虑它。并且加入一个老鼠的时候,只考虑在她左边的洞
加入一个洞的时候可能会出现这样的事情:
image
出现一个负环。
那么事情就变得简单了:加入老鼠的时候,查询前面没被使用过的最左的洞;避免没有的情况,可以加一个极远的洞。而加入洞的时候,考虑前面被使用过的最【?】的洞,判一下环的权值是不是负数,是的话就增广掉。
然后这个【?】,实际上是 老鼠和洞的距离 加 老鼠的坐标 作为关键字。这样更容易出负环。画个图不难理解。

用两个堆维护就好。

Task 2

CF865D
建图是 trivial 的。考虑每次新增一支股票,会出现什么样的增广。
考虑到唯一有可能的正环就是,把之前某一次卖出 put off,改到今天卖掉。
那这个容易用堆维护,带上正常增广一起搞。复杂度 \(O(n\log n)\)

Task 3

续 Task 1,每个洞的容量可能不为 \(1\),是一个正整数 \(c_i\)

  • 神仙做法

先钦定每个老鼠只能向左跑,做一遍,取出洞的集合;再钦定只能向右跑,做一遍,取出洞的集合。两个并到一起,总大小就是 \(O(n)\) 的,然后拆成单点做 Task 1 就好。

  • 证明(直接贺过来)
    从第一遍贪心到原问题,对于每一个洞而言,从它右边出发到达
    它左边的老鼠不会变多。
    从第二遍贪心到原问题,对于每一个洞而言,从它左边出发到达
    它右边的老鼠不会变多。

  • 另一种做法(人类能想到的)
    把堆的类型改成 pair。新增鼠鼠的操作不变,新增洞的操作,直接改成,枚举满堆的堆顶,增广直到圈为非负。
    复杂度是对的,因为每次增广会使得一只鼠鼠由向左变为向右。故总复杂度是 \(O(n)\) 的。

Task 4

P6943
续 Task 1,相当于把数轴变成了树,坐标改成深度。\(y\) 相当于老鼠,\(x\) 相当于洞。然后洞的容量是假的,可以直接拆成 1e6 个单点(好像套 Task 3 的方法也行?)。
续用 Task 1 的堆的做法,改成可并堆。

然后子树合并的位置是有一点细节的。具体地,需要计算被占掉点 \(x\) 的的“等效深度”。算出来的结论是,\(2dep_u-dep_x\)。然后合并的时候,对于子树 \(u\),暴力枚举空洞堆里面的空洞,合并上去就好。复杂度的证明仿照 Task 3,反悔的次数是 \(O(deg_u)\) 的,是没有问题的。\(O(V\log V)\)

Task 5

洞有额外代价 \(w_i\)

核心矛盾在于,一个老鼠反悔而匹配了右边的一个洞之后,她可能会继续反悔去更右边的洞。再开一个堆的事情。
额好吧实际上也没啥区别,就相当于这个洞用过了还能再加进堆里。Task 1 加了也没错,只是没必要。

注意一个洞在被路径增广后,和被负环增广后的“等效坐标”是不一样的。特殊处理一下就好。
不用记录多元组,队里只需要维护等效坐标就好。

Task 6

UOJ455
Task 3 + Task 5。注意判 0。

Bonus:能不能证明或证伪,Task 3 的【神仙做法】用在这一题是否正确?(至今好像无人破解)

Task 7

P5470
反正不告诉我,我一眼看不到他是一个流子。
考虑建图。想一想怎么限制【最少 \(L\) 个相同的】。
那说白了他最多 \(K-L\) 个不同的。注意这是一个全局限制,所以弄一些点全局限流。(没想出来脑袋被敲烂了。)
image

然后限制总流量为 \(K\)

哎那我们沿用之前的方法,考虑新加一个点他会变成什么样,直观看来他需要一个 wqs 把最大费用最大流变成最大费用可行流。那过个蛋。

一个想法是,先自由流,即选出前 \(x\) 大的 \(a_i\),选出前 \(x\) 大的 \(b_i\),让她们自由匹配。但这个 \(x\) 是不可二分的。

然后考虑一条增广路会是什么形态的。
第一种,不退 \(p\to q\) 的情况,大概是 \(s(\to i_1 \to p) \to j_1 \to j_2 (\to q \to k_2) \to t\)。括号表示过程可以省略。
第二种,退 \(p \to q\) 的情况,只会出现 \(s\to i_1 \to i_2 \to q \to p \to j_1 \to j_2 \to t\)
第三种,用 \(p\to q\) 的情况。\(s\to i_1 \to p \to q \to k_2\)
(这里因为 Dinic 总是无正环的,所以和 \(s/t\) 相连的边不会退流。)

分讨一下,五个堆维护,且动态维护 \(p\to q\) 的剩余流量。好写好调。
想起来有点复杂。

总结
这一题和前面老鼠进洞的模型不同点在于,这一题不适用 增量-增广 模型。
前面的题必须要用 增量-增广 的原因在于,她有横向边,直接去 Dinic 搞不出来横向边的反悔操作。

这一题有费用的边只有 \(s\) 相连的,和 \(t\) 相连的。那就很好直接做了。

闵可夫斯基和

为什么放在这里写?因为不想新建一个文章。
从这里开始 /bx Flying2018,文章和程序设计都很漂亮。有的程序看了一眼之后写出来就差不多了。

闵可夫斯基和,用于优化一类包含 \((\min/\max,+)\) 转移的 DP。
常规的闵和是 \(O(|A|+|B|)\) 的。但是如果你放在树上就可以写一个启发式合并的 set 或者平衡树直接往差分数组里面 insert。偷懒做法属于是。单次复杂度是 \(O(\min(|A|,|B|)\log)\) 的。

a simple task

考虑 wqs 的经典问题。给定一个长度为 \(n\) 的数组 \(a\),给定 \(k\),求 \(a\) 中取 \(k\) 个不相交子段的最大总和。
费用流模型是容易建出来的。所以有图形。
现在我要对 \(\forall k \in [1, n]\) 求这个问题。那 wqs 就 4 了。

考虑朴素 DP,记 \(f_{l,r,i,0/1,0/1}\) 表示我在 \([l,r]\) 中,钦定 \(l\) 任意或一定不选,钦定 \(r\) 任意或一定不选,选了 \(i\) 段。
(这里的 \([l, r]\) 并不是真正意义上区间 DP。转移的时候,分割点是可以任选的。)
转移是平凡的。特殊地,可以 \(f_{l,r,i+j-1,0/1,0/1}\gets f_{l,x,i,0/1,1}+f_{x+1,r,j,1,0/1}\)。表示中间一段缩成一段了。

然后这里上 Minkowski 和,就可以在 \(O(len)\) 的复杂度内做掉一个区间合并。取转移点为区间中点,复杂度 \(T(n)=2T(\frac n2)+O(n)\),得 \(T(n)=O(n\log n)\)

QOJ7417

这题加了一个多组区间询问。Minkowski 和最令人难受的一点就是,他合并的复杂度是 \(O(|A|+|B|)\)

我没见过这个技巧。想不到认输了。
考虑线段树处理询问。回答询问的时候显然不能直接把总长度为 \(O(len)\)\(O(\log n)\) 个凸包并起来。那咋办。
wqs 又活了。这时候二分一个惩罚 \(w\),然后再在这 \(\log\) 个凸包上二分斜率。哦哦哦原来可以二分套二分啊,我以前只见过 wqs 之后线性及以上 check 的。

那这时候你复杂度是三个老哥的。(某人告诉)过不去。
整体 wqs 二分。(?)

和整体二分有点区别的。具体地,比如我二分到某一层,然后我给 \(q\) 个询问一起做。那这时候会制造出来 \(O(q\log n \log V)\) 个二分的询问。然后我给这些挂到线段树的结点上,平均每个结点 \(\log\) 个。
然后对于这些询问,我们不再二分切点;而是给询问排序,然后在凸包上暴力地移动一个指针。询问递减,指针也不会回退。那么指针的总移动次数是 \(O(n\log n)\) 的,惩罚二分 \(\log V\) 次,总复杂度 \(O(n\log n \log V + q\log n \log V)\)。可以通过。

写过了就有资格说好写好调了。

Gym102331J

那这题不难写出一个转移 \(f_{u,0/1}(i)\) 表示,匹配大小为 \(i\)\(u\) 强制不在/强制在匹配里面。
然后转移大概是

\[f_{u,0}\gets f_{u,0}\times f_{v,1} \]

\[f_{u,1}\gets \max(f_{u,1}\times f_{v,1},f_{u,0}\times (f_{v,0}+w)) \]

乘号表示 \((\max,+)\) 卷积。

然后这道题把启发式合并 ban 掉了,因为你有一个对凸包取 max 的操作。
(凸包和凸包取 max 不一定是凸包,这里还是凸包的原因是他是一个费用流模型。)
有人说你 \(f_{u,1}\) 强制在匹配里面,不一定是凸的啊,因为他不一定是最优的。(这扯不扯,你把 \(u\) 看成一个流量下界不就完事。对不起这句话是错的。有下界的费用流,凸性得在他有解的时候才成立啊!)
哦所以得把上面的转移微调一下,但也是不难的。


你想,为什么分治 FFT 不能一个一个乘,复杂度会爆炸?
考虑分治。归并左右两边的答案,那在 \(u\) 处的复杂度就是 \(O(sz_u\log sz_u)\) 的。
那造一个链还是爆掉了。

考虑重链剖分。具体地,每次在 \(u\) 处按照上面的过程暴力合并轻儿子的凸包,挂在 \(u\) 上,记为 \(g_u\)。然后因为轻子树的大小之和是 \(O(n\log n)\) 的,所以这部分是没有问题的。
然后考虑重链。每次做重链的时候,仅在链顶合并,把重链里面的所有 \(g_u\) 分治地合并起来就好。链顶的 \(sz\) 之和,也是 \(O(n\log n)\) 的。

也就是需要实现这两个分治:
image
image
大概就是,分治的时候返回一个 pair,就差不多。
哦对,solve2 的时候,要记录左右端点是不是被强制没匹配上。
总复杂度两个老哥。不卡常。

QOJ10706

额虽然但是这个题和 Minkowski 没关系,但是也是对于所有的 \(k=0,1,\dots, n-1\) 求出答案。

但是你 wqs 怎么做多组询问。
wqs 二分也是二分,可以考虑类似整体二分的手法。
那么这里就是要均摊掉一些重复计算的复杂度,使得总复杂度可以接受。

考虑我二分红边的奖励代价 \(w\)(意思就是每条红边代价减 \(w\)),那么,我 \(w\) 越大,红边越多。
那这里有个关键性质:我现在用奖励代价 \(w\) 算出来了一个 MST,这个 MST 里面的红边,在 \(w\) 增大的时候是仍然保留的!蓝边同理,在 \(w\) 减少的时候仍然保留!没选入 MST 的蓝边,在 \(w\) 变大的时候一定没用!没选入 MST 的红边同理。

那么这里整体二分,求 MST 的时候用并查集缩合一下,那么可以使得每层递归的总边数是 \(O(m)\) 的。然后回来的时候撤销一下就好。
复杂度大概是 \(O((n+m)\log n \log m)\) 的。

posted @ 2026-01-21 20:30  Water_M  阅读(32)  评论(1)    收藏  举报