【题目链接】
【思路要点】
- 最小割,考虑在为每个元素 i i i 在源汇之间建点 p o i n t i , 0 point_{i,0} pointi,0 ,连边 ( s , p o i n t i , 0 , b i ) , ( t , p o i n t i , 1 , w i ) (s,point_{i,0},b_i),(t,point_{i,1},w_i) (s,pointi,0,bi),(t,pointi,1,wi) ,此时的最小割即为无视限制条件时的最小损失。
- 建立辅助点 p o i n t i , 1 point_{i,1} pointi,1 ,连边 ( p o i n t i , 0 , p o i n t i , 1 , p i ) (point_{i,0},point_{i,1},p_i) (pointi,0,pointi,1,pi) ,并对于所有的满足限制条件的 j j j , ( p o i n t i , 1 , p o i n t j , 0 , + ∞ ) (point_{i,1},point_{j,0},+\infty) (pointi,1,pointj,0,+∞) ,此时的最小割就可以考虑限制条件了。
- 用线段树优化建图即可。
- 时间复杂度 O ( D i n i c ( N L o g N , N L o g N ) ) O(Dinic(NLogN,NLogN)) O(Dinic(NLogN,NLogN)) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5005; const int MAXP = 2e5 + 5; const int INF = 1e9; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } namespace NetworkFlow { const int INF = 2e9; const int MAXP = 2e5 + 5; struct edge { int dest, flow; unsigned pos; }; vector <edge> a[MAXP]; int tot, s, t, dist[MAXP]; unsigned curr[MAXP]; void addedge(int x, int y, int z) { a[x].push_back((edge) {y, z, a[y].size()}); a[y].push_back((edge) {x, 0, a[x].size() - 1}); } int dinic(int pos, int limit) { if (pos == t) return limit; int used = 0, tmp; for (unsigned &i = curr[pos]; i < a[pos].size(); i++) if (a[pos][i].flow != 0 && dist[pos] + 1 == dist[a[pos][i].dest] && (tmp = dinic(a[pos][i].dest, min(limit - used, a[pos][i].flow)))) { used += tmp; a[pos][i].flow -= tmp; a[a[pos][i].dest][a[pos][i].pos].flow += tmp; if (used == limit) return used; } return used; } bool bfs() { static int q[MAXP]; int l = 0, r = 0; memset(dist, 0, sizeof(dist)); dist[s] = 1, q[0] = s; while (l <= r) { int tmp = q[l]; for (unsigned i = 0; i < a[tmp].size(); i++) if (dist[a[tmp][i].dest] == 0 && a[tmp][i].flow != 0) { q[++r] = a[tmp][i].dest; dist[q[r]] = dist[tmp] + 1; } l++; } return dist[t] != 0; } int flow() { int ans = 0; while (bfs()) { memset(curr, 0, sizeof(curr)); ans += dinic(s, INF); } return ans; } } int n, ans, tot, point[MAXN][2]; int a[MAXN], b[MAXN], g[MAXN]; int l[MAXN], r[MAXN], p[MAXN]; int home[MAXN], rk[MAXN]; struct SegmentTree { struct Node { int lc, rc; } a[MAXP]; int root; int build(int l, int r) { if (l == r) return 0; int root = ++tot, mid = (l + r) / 2; a[root].lc = build(l, mid); a[root].rc = build(mid + 1, r); if (a[root].lc) NetworkFlow :: addedge(root, a[root].lc, INF); if (a[root].rc) NetworkFlow :: addedge(root, a[root].rc, INF); return root; } void init() { root = build(1, n); } int modify(int root, int l, int r, int pos, int res) { if (l == r) return res; int ans = ++tot, mid = (l + r) / 2; a[ans] = a[root]; if (mid >= pos) a[ans].lc = modify(a[root].lc, l, mid, pos, res); else a[ans].rc = modify(a[root].rc, mid + 1, r, pos, res); if (a[ans].lc) NetworkFlow :: addedge(ans, a[ans].lc, INF); if (a[ans].rc) NetworkFlow :: addedge(ans, a[ans].rc, INF); return ans; } void modify(int pos, int res) { root = modify(root, 1, n, pos, res); } void query(int root, int l, int r, int ql, int qr, int pos) { if (l == ql && r == qr) { NetworkFlow :: addedge(pos, root, INF); return; } int mid = (l + r) / 2; if (mid >= ql) query(a[root].lc, l, mid, ql, min(qr, mid), pos); if (mid + 1 <= qr) query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, pos); } void query(int pos, int ql, int qr) { query(root, 1, n, ql, qr, pos); } } ST; bool cmp(int x, int y) { return a[x] < a[y]; } int main() { read(n); NetworkFlow :: s = 1; NetworkFlow :: t = tot = 2; for (int i = 1; i <= n; i++) { point[i][0] = ++tot; point[i][1] = ++tot; read(a[i]), read(b[i]), read(g[i]); read(l[i]), read(r[i]), read(p[i]); ans += b[i] + g[i]; home[i] = i; } sort(home + 1, home + n + 1, cmp); for (int i = 1; i <= n; i++) rk[home[i]] = i; ST.init(); for (int i = 1; i <= n; i++) { NetworkFlow :: addedge(NetworkFlow :: s, point[i][0], b[i]); NetworkFlow :: addedge(point[i][0], NetworkFlow :: t, g[i]); NetworkFlow :: addedge(point[i][0], point[i][1], p[i]); int ql = 0, qr = 0; for (int j = 1; j <= n; j++) if (l[i] <= a[home[j]] && r[i] >= a[home[j]]) { if (ql == 0) ql = j; qr = j; } if (ql != 0) ST.query(point[i][1], ql, qr); ST.modify(rk[i], point[i][0]); } ans -= NetworkFlow :: flow(); writeln(ans); return 0; }