Loading

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;
}
posted @ 2024-06-03 17:47  JiaY19  阅读(3)  评论(0编辑  收藏  举报