P5029 T'ill It's Over 题解
思路
考虑最大流。
线段树优化网络流板子题。
容易发现原题是网络流形式。
套一个线段树优化建图即可。
具体的。
我们可以建出两颗线段树。
在第一颗线段树中,连 \((L_p,p,inf),(R_p,p,inf)\)。
在第二颗线段树中,连 \((p,L_p,inf),(p,R_p,inf)\)。
另外在叶子节点处,连 \((p_2,p_1,inf)\)。
发现所有的操作都被操作 \(4\) 包含。
我们可以建两个虚拟节点 \(x,y\),连 \((x,y,l)\)。
把第一个线段树的对应区间连向 \(x\)。
把 \(y\) 连向第二个线段树的对应区间。
最后,在第一颗线段树上,连 \((s,1,n),(k,t,n)\),其中 \(1,t\) 分别代表对应的叶子节点。
Code
/*
! 如果没有天赋,那就一直重复
! Created: 2024/06/03 15:10:11
*/
#include <bits/stdc++.h>
using namespace std;
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
struct NetWork {
using i64 = long long;
struct edge { int to, nxt; i64 v; };
int ct, n, s, t; i64 mf;
vector<edge> e;
vector<int> dp, gp, cr, hd;
inline NetWork(int N) {
n = N, ct = 1;
dp.resize(N + 5), gp.resize(N + 5);
cr.resize(N + 5), hd.resize(N + 5);
e.push_back({}), e.push_back({});
}
inline void add(int x, int y, int z) {
e.push_back({y, hd[x], z}), hd[x] = ++ct;
e.push_back({x, hd[y], 0}), hd[y] = ++ct;
}
inline void bfs() {
queue<int> q;
fill(dp.begin(), dp.end(), 0);
fill(gp.begin(), gp.end(), 0);
q.push(t), gp[dp[t] = 1] = 1;
while (q.empty() == 0) {
int x = q.front(); q.pop();
for (int i = hd[x]; i; i = e[i].nxt) {
if (!dp[e[i].to]) {
gp[dp[e[i].to] = dp[x] + 1]++;
q.push(e[i].to);
}
}
}
}
inline i64 dfs(int now, i64 flow) {
if (now == t) return mf += flow, flow;
i64 used = 0;
for (int&i = cr[now]; i; i = e[i].nxt) {
if (dp[e[i].to] + 1 == dp[now] && e[i].v) {
int x = dfs(e[i].to, min(e[i].v, flow - used));
e[i].v -= x, e[i ^ 1].v += x, used += x;
if (used == flow) return used;
}
}
if (--gp[dp[now]] == 0) dp[s] = n + 1;
return gp[++dp[now]]++, used;
}
inline i64 isap(int S, int T) {
s = S, t = T, mf = 0, bfs();
while (dp[s] <= n) copy(hd.begin(), hd.end(), cr.begin()), dfs(s, 1e18);
return mf;
}
};
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
int n, m, k, s, t, ct = 0;
cin >> n >> m >> k;
vector<int> d1(2 * k);
vector<int> d2(2 * k);
NetWork sol(4 * k + 2 * m);
auto build = [&](int p, int l, int r, auto build) -> void {
d1[p] = ++ct, d2[p] = ++ct;
if (l == r) {
sol.add(d2[p], d1[p], 1e9);
if (l == 1) s = ++ct, sol.add(s, d1[p], n);
if (l == k) t = ++ct, sol.add(d1[p], t, n);
return;
}
int mid = (l + r) >> 1;
build(mid<<1, l, mid, build);
build(mid<<1|1, mid + 1, r, build);
sol.add(d1[mid<<1], d1[p], 1e9);
sol.add(d1[mid<<1|1], d1[p], 1e9);
sol.add(d2[p], d2[mid<<1], 1e9);
sol.add(d2[p], d2[mid<<1|1], 1e9);
};
auto upd = [&](int p, int l, int r, int L, int R, int k, int op, auto upd) -> void {
if (L <= l && r <= R) {
if (op == 0) sol.add(d1[p], k, 1e9);
if (op == 1) sol.add(k, d2[p], 1e9);
return;
}
int mid = (l + r) >> 1;
if (mid >= L) upd(mid<<1, l, mid, L, R, k, op, upd);
if (mid < R) upd(mid<<1|1, mid + 1, r, L, R, k, op, upd);
};
build(1, 1, k, build);
fro(i, 1, m) {
int op, l, a1, a2, b1, b2, x, y;
cin >> op >> l, sol.add(x = ++ct, y = ++ct, l);
if (op == 1) cin >> a1 >> b1, a2 = a1, b2 = b1;
if (op == 2) cin >> a1 >> a2 >> b1, b2 = b1;
if (op == 3) cin >> a1 >> b1 >> b2, a2 = a1;
if (op == 4) cin >> a1 >> a2 >> b1 >> b2;
upd(1, 1, k, a1, a2, x, 0, upd);
upd(1, 1, k, b1, b2, y, 1, upd);
}
cout << sol.isap(s, t) << "\n";
return 0;
}