CF903G Yet Another Maxflow Problem 题解
注意到最大流不好处理,而众所周知最大流等于最小割,因此考虑求出最小割。
最小割:将若干条有向边断开使得源点汇点不连通,这些有向边的边权和最小值。
首先注意到我们只可能会在 中断掉一条边 ,具体证明就是如果断了两条边,那么后面那条边断了也是白断,因为源点无法通过 中的点到达后面的边, 又没有向 连的边,因此显然不优。同理, 中也只会断掉一条边。
设 表示 中断掉 , 中断掉 时最小割大小,此时我们需要将 到 中所有点都要断掉,因此有计算式:
其中 表示 的边权, 类似, 表示 的边权,没有记为 0。
然后注意到修改操作中只会修改 ,因此后面这坨东西对于每一个 实际上是定的,令 ,考虑如何快速维护 。
考虑从小到大枚举 ,在 上建立一棵线段树,每个节点维护当前枚举到 时区间 内 的最小值,考虑枚举 出边 ,注意到会被影响到的实际上是个前缀 ,区间修改即可,改完后 就是根节点最小值。
于是问题变成了每次求 ,随便维护一下就好了。
但是有个讨厌的地方,就是可能 A 里面可以没有点断掉,B 里面也可以没有点断掉,这样和上面分析过程不符(因为上面要求两边必须都要断),因此在两边另外连两条边 ,边权全是 0,表示如果没有边断掉那么就断这两条边,你会发现这样本质上没有改变图的任何性质但是有断边了。
代码里面是将所有 点往后移了一个位置然后令 重标号为 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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具