CF903G Yet Another Maxflow Problem 题解

注意到最大流不好处理,而众所周知最大流等于最小割,因此考虑求出最小割。

最小割:将若干条有向边断开使得源点汇点不连通,这些有向边的边权和最小值。

首先注意到我们只可能会在 A 中断掉一条边 AxAx+1,具体证明就是如果断了两条边,那么后面那条边断了也是白断,因为源点无法通过 A 中的点到达后面的边,B 又没有向 A 连的边,因此显然不优。同理,B 中也只会断掉一条边。

fx,y 表示 A 中断掉 AxAx+1B 中断掉 ByBy+1 时最小割大小,此时我们需要将 A1,...,xBy+1,...,n 中所有点都要断掉,因此有计算式:

fx,y=ax+by+ixj>ydi,j

其中 ax 表示 AxAx+1 的边权,by 类似,di,j 表示 AiBj 的边权,没有记为 0。

然后注意到修改操作中只会修改 ax,因此后面这坨东西对于每一个 x 实际上是定的,令 cx=by+ixj>ydi,j,考虑如何快速维护 cx

考虑从小到大枚举 x,在 {bn} 上建立一棵线段树,每个节点维护当前枚举到 x 时区间 y[l,r]cx 的最小值,考虑枚举 x 出边 xy,注意到会被影响到的实际上是个前缀 [1,y1],区间修改即可,改完后 cx 就是根节点最小值。

于是问题变成了每次求 min{ax+cx},随便维护一下就好了。

但是有个讨厌的地方,就是可能 A 里面可以没有点断掉,B 里面也可以没有点断掉,这样和上面分析过程不符(因为上面要求两边必须都要断),因此在两边另外连两条边 AnAn+1,B0B1,边权全是 0,表示如果没有边断掉那么就断这两条边,你会发现这样本质上没有改变图的任何性质但是有断边了。

代码里面是将所有 B 点往后移了一个位置然后令 B0 重标号为 1。

Code:

/*
========= Plozia =========
	Author:Plozia
	Problem:CF903G Yet Another Maxflow Problem
	Date:2022/10/25
========= Plozia =========
*/

#include <bits/stdc++.h>
typedef long long LL;

const int MAXN = 2e5 + 5;
int n, m, Head[MAXN], cntEdge, q;
LL a[MAXN], b[MAXN], c[MAXN];
struct node { int To; LL val; int Next; } Edge[MAXN << 1];
struct SgT { LL Minn, tag; } tree[MAXN << 2];
#define Minn(p) tree[p].Minn
#define tag(p) tree[p].tag

int Read()
{
	int sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
	return sum * fh;
}
void add(int x, int y, int z) { ++cntEdge; Edge[cntEdge] = (node){y, z, Head[x]}; Head[x] = cntEdge; }
LL Min(LL fir, LL sec) { return (fir < sec) ? fir : sec; }

void Update(int p) { Minn(p) = Min(Minn(p << 1), Minn(p << 1 | 1)); }
void Spread(int p)
{
	Minn(p << 1) += tag(p), Minn(p << 1 | 1) += tag(p);
	tag(p << 1) += tag(p), tag(p << 1 | 1) += tag(p); tag(p) = 0;
}
void Build(int p, int lp, int rp)
{
	tag(p) = 0; if (lp == rp) { Minn(p) = b[lp]; return ; } int mid = (lp + rp) >> 1;
	Build(p << 1, lp, mid); Build(p << 1 | 1, mid + 1, rp); Update(p);
}
void Add(int p, int l, int r, LL x, int lp, int rp)
{
	if (lp >= l && rp <= r) { Minn(p) += x, tag(p) += x; return ; }
	int mid = (lp + rp) >> 1; Spread(p);
	if (l <= mid) Add(p << 1, l, r, x, lp, mid);
	if (r > mid) Add(p << 1 | 1, l, r, x, mid + 1, rp);
	Update(p);
}

int main()
{
	n = Read(), m = Read(), q = Read();
	for (int i = 1; i < n; ++i) a[i] = Read(), b[i + 1] = Read();
	for (int i = 1; i <= m; ++i) { int x = Read(), y = Read(), z = Read(); add(x, y, z); }
	Build(1, 1, n);
	for (int i = 1; i <= n; ++i)
	{
		for (int j = Head[i]; j; j = Edge[j].Next) Add(1, 1, Edge[j].To, Edge[j].val, 1, n);
		c[i] = Minn(1);
	}
	for (int i = 1; i <= n; ++i) b[i] = a[i] + c[i];
	Build(1, 1, n); printf("%lld\n", Minn(1));
	for (int i = 1; i <= q; ++i)
	{
		int x = Read(), y = Read(); Add(1, x, x, y - a[x], 1, n); a[x] = y;
		printf("%lld\n", Minn(1));
	}
	return 0;
}
posted @   Plozia  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示