1 条题解
-
1
让我们重新表述一下这个问题:构建一个网络流模型, 流量为 , 流量为 , 流量为 。
要求改变区间后,对每个 求出最大流。
回忆 Hall 定理:
- 一个二分图对右部点有完美匹配,当且仅当对于任何右部点集合 满足 ;
- 推广:一个带权二分图对右部点有带权完美匹配,当且仅当对于任何右部点集合 满足 。
设 ,。此处的完美匹配就是 。由于 Hall 定理只给出了完美匹配的标准,我们必须修改它让它能够计算最大流。比如说,增加一个能被所有磁铁匹配的权值为 的铁钉,那么:只要 ,我们就能断言最大流的值,因此我们只要找到 (再次注意, 是磁铁,而 是铁钉)。
固定 ,我们想要最大化 ,可以加入所有使 不变的磁铁,那么对于 ,如果 的磁铁编号最大为 , 的磁铁编号最小为 ,那么显然可以加入 的所有磁铁。
令 表示 , 表示 的铁钉的 之和。固定 ,显然
$$X - Y = \sum_{i=1}^m c_i - \sum_{i=l+1}^{r-1} c_i - \sum_{i=1}^n a_i + a[l + 1, r - 1] $$删去容易计算的常量,我们只考虑 ,也就是 。排除掉平凡的情况(如果 或 ,我们事实上相当于可以加入所有的 和所有的 ),我们只考虑用 对 的所有 快速 。
我们采用分治的方式解决上述问题。让我们设 表示解决 的所有问题。
首先,取 并递归解决。然后我们便只关心 , 的问题。显然这个问题对于 和 又不同了,如果仅考虑 :显然 一端的后缀我们只要取一个最大值即可,线段树维护,于是扫描一下 。另一侧同理。
需要一颗线段树支持区间 次,另一颗线段树支持区间加、区间 次,复杂度是 的。
std::vector<std::pair<int, int>> Rp[MAXN], Lp[MAXN]; void dc_L(int l, int r) { if (l == r) { for (auto [r, v] : Rp[l]) T2::add(r, N, v); T1::chkmax(l, l, T2::query(l, l) + s[l - 1]); return; } int mid = l + r >> 1; dc_L(mid + 1, r); for (int k = mid; k >= l; --k) { for (auto [r, v] : Rp[k]) T2::add(r, N, v); long long val = T2::query(mid + 1, r) + s[k - 1]; T1::chkmax(k, mid, val); } for (int k = l; k <= mid; ++k) for (auto [r, v] : Rp[k]) T2::add(r, N, -v); dc_L(l, mid); } void dc_R(int l, int r) { if (l == r) { for (auto [l, v] : Lp[r]) T2::add(1, l, v); T1::chkmax(r, r, T2::query(r, r) - s[r]); return; } int mid = l + r >> 1; dc_R(l, mid); for (int k = mid + 1; k <= r; ++k) { for (auto [l, v] : Lp[k]) T2::add(1, l, v); long long val = T2::query(l, mid) - s[k]; T1::chkmax(mid + 1, k, val); } for (int k = mid + 1; k <= r; ++k) for (auto [l, v] : Lp[k]) T2::add(1, l, -v); dc_R(mid + 1, r); }
可以通过限制区间范围和减少区间撤销、减少 操作等方式来卡常(在上述代码中没有展示出来,请选手各显神通)。
这里的 Hall 定理形式与最小割几乎类似,就留给读者细究。
- 1
信息
- ID
- 800
- 时间
- 1000~5000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 18
- 已通过
- 4
- 上传者