线段树优化建图+费用流
朴素的做法是每个强盗直接对每个区间的每个点连边,然后跑最大权匹配,这样有5000*5000条边,肯定过不去,那么我们用线段树优化一下,因为线段树能把一个O(n)的区间划分为O(logn)段
然后就建一棵线段树,每个节点向两个儿子连(inf,0)的边,叶子结点连向sink,(1,0),每个强盗向对应区间节点连边,这样边数就将为了nlogn条。据说正解是贪心?
抄了个板子
#include<bits/stdc++.h> using namespace std; const int N = 30010, inf = 0x3f3f3f3f; struct edge { int nxt, to, f, c; } e[N * 100]; int n, m, k, source, sink, tot, cnt = 1, sum; int head[N], pree[N], prev[N], vis[N], d[N]; inline void link(int u, int v, int f, int c) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].f = f; e[cnt].to = v; e[cnt].c = c; } inline void insert(int u, int v, int f, int c) { link(u, v, f, c); link(v, u, 0, -c); } bool spfa() { memset(d, -1, sizeof(d)); d[source] = 0; queue<int> q; q.push(source); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && (d[e[i].to] < d[u] + e[i].c || d[e[i].to] == -1)) { pree[e[i].to] = i; prev[e[i].to] = u; d[e[i].to] = d[u] + e[i].c; if(vis[e[i].to] == 0) { q.push(e[i].to); vis[e[i].to] = 1; } } } return d[sink] != -1; } inline int Edmonds_Karp() { int ans = 0; while(spfa()) { int now = sink, delta = inf; while(now != source) { delta = min(delta, e[pree[now]].f); now = prev[now]; } now = sink; while(now != source) { e[pree[now]].f -= delta; e[pree[now] ^ 1].f += delta; now = prev[now]; } ans += delta * d[sink]; } return ans; } void build(int l, int r, int x) { if(l == r) { insert(x, sink, 1, 0); return; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); insert(x, x << 1, inf, 0); insert(x, x << 1 | 1, inf, 0); } void update(int l, int r, int x, int a, int b, int c, int pos) { if(l > b || r < a) return; if(l >= a && r <= b) { insert(pos, x, 1, c); return; } int mid = (l + r) >> 1; update(l, mid, x << 1, a, b, c, pos); update(mid + 1, r, x << 1 | 1, a, b, c, pos); } int main() { scanf("%d", &n); sink = 20000 + n + 1; build(1, 5000, 1); for(int i = 1; i <= n; ++i) { int l, r, c; scanf("%d%d%d", &l, &r, &c); insert(source, i + 20000, 1, 0); update(1, 5000, 1, l, r - 1, c, i + 20000); } printf("%d ", Edmonds_Karp()); return 0; }