主要思路
这道题还是很妙的,我只想到了最大费用最大流之后就想不动了。
我们在这里介绍边数为\(O(n)\)级别的解法。考虑把所有的端点离散化为\(2n\)个连续的点,然后相邻端点\(i, i+1\)相互连接流量无限、费用为零的边。考虑区间左右端点,左端点连到右端点,流量为\(1\),费用为区间长度。最后源点连左端点,汇点连到右端点。
这样就可以强制满流,且费用最大。
代码
// LOJ6014.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2e5 + 200, INF = 0x3f3f3f3f;
int head[MAX_N], current, pre[MAX_N], dist[MAX_N];
int st, ed, flow[MAX_N], n, k, mx_range;
bool vis[MAX_N];
vector<int> vec;
struct segment
{
int l, r;
} segs[MAX_N];
struct edge
{
int to, weight, cost, nxt;
} edges[MAX_N << 1];
void addpath(int src, int dst, int weight, int cst)
{
edges[current].to = dst, edges[current].weight = weight;
edges[current].cost = cst, edges[current].nxt = head[src];
head[src] = current++;
}
void addtube(int src, int dst, int weight, int cst)
{
addpath(src, dst, weight, cst);
addpath(dst, src, 0, -cst);
}
bool bfs()
{
memset(dist, 0x3f, sizeof(dist)), memset(vis, false, sizeof(vis));
queue<int> q;
q.push(st), vis[st] = true, flow[st] = INF, dist[st] = 0;
while (!q.empty())
{
int u = q.front();
vis[u] = false;
q.pop();
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].weight > 0 && dist[edges[i].to] > dist[u] + edges[i].cost)
{
dist[edges[i].to] = dist[u] + edges[i].cost;
flow[edges[i].to] = min(flow[u], edges[i].weight);
pre[edges[i].to] = i;
if (!vis[edges[i].to])
vis[edges[i].to] = true, q.push(edges[i].to);
}
}
return dist[ed] != INF;
}
int mcmf()
{
long long ans = 0;
while (bfs())
{
int p = ed, i = pre[p];
ans += 1LL * flow[ed] * dist[ed];
while (p != st)
{
edges[i].weight -= flow[ed], edges[i ^ 1].weight += flow[ed];
p = edges[i ^ 1].to, i = pre[p];
}
}
return ans;
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &segs[i].l, &segs[i].r);
if (segs[i].l > segs[i].r)
swap(segs[i].l, segs[i].r);
vec.push_back(segs[i].l), vec.push_back(segs[i].r);
}
vec.push_back(-0x3f3f3f3f);
sort(vec.begin(), vec.end());
st = 0, ed = 2 * n + 1;
addtube(st, 1, k, 0);
for (int i = 1; i < 2 * n; i++)
addtube(i, i + 1, INF, 0);
addtube(2 * n, ed, k, 0);
for (int i = 1; i <= n; i++)
{
int len = segs[i].r - segs[i].l;
segs[i].l = lower_bound(vec.begin(), vec.end(), segs[i].l) - vec.begin();
segs[i].r = lower_bound(vec.begin(), vec.end(), segs[i].r) - vec.begin();
addtube(segs[i].l, segs[i].r, 1, -len);
}
printf("%d", -mcmf());
return 0;
}
// LOJ6014.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2e5 + 200, INF = 0x3f3f3f3f;
int head[MAX_N], current, pre[MAX_N], dist[MAX_N];
int st, ed, flow[MAX_N], n, k, mx_range;
bool vis[MAX_N];
vector<int> vec;
struct segment
{
int l, r;
} segs[MAX_N];
struct edge
{
int to, weight, cost, nxt;
} edges[MAX_N << 1];
void addpath(int src, int dst, int weight, int cst)
{
edges[current].to = dst, edges[current].weight = weight;
edges[current].cost = cst, edges[current].nxt = head[src];
head[src] = current++;
}
void addtube(int src, int dst, int weight, int cst)
{
addpath(src, dst, weight, cst);
addpath(dst, src, 0, -cst);
}
bool bfs()
{
memset(dist, 0x3f, sizeof(dist)), memset(vis, false, sizeof(vis));
queue<int> q;
q.push(st), vis[st] = true, flow[st] = INF, dist[st] = 0;
while (!q.empty())
{
int u = q.front();
vis[u] = false;
q.pop();
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].weight > 0 && dist[edges[i].to] > dist[u] + edges[i].cost)
{
dist[edges[i].to] = dist[u] + edges[i].cost;
flow[edges[i].to] = min(flow[u], edges[i].weight);
pre[edges[i].to] = i;
if (!vis[edges[i].to])
vis[edges[i].to] = true, q.push(edges[i].to);
}
}
return dist[ed] != INF;
}
int mcmf()
{
long long ans = 0;
while (bfs())
{
int p = ed, i = pre[p];
ans += 1LL * flow[ed] * dist[ed];
while (p != st)
{
edges[i].weight -= flow[ed], edges[i ^ 1].weight += flow[ed];
p = edges[i ^ 1].to, i = pre[p];
}
}
return ans;
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &segs[i].l, &segs[i].r);
if (segs[i].l > segs[i].r)
swap(segs[i].l, segs[i].r);
vec.push_back(segs[i].l), vec.push_back(segs[i].r);
}
vec.push_back(-0x3f3f3f3f);
sort(vec.begin(), vec.end());
st = 0, ed = 2 * n + 1;
addtube(st, 1, k, 0);
for (int i = 1; i < 2 * n; i++)
addtube(i, i + 1, INF, 0);
addtube(2 * n, ed, k, 0);
for (int i = 1; i <= n; i++)
{
int len = segs[i].r - segs[i].l;
segs[i].l = lower_bound(vec.begin(), vec.end(), segs[i].l) - vec.begin();
segs[i].r = lower_bound(vec.begin(), vec.end(), segs[i].r) - vec.begin();
addtube(segs[i].l, segs[i].r, 1, -len);
}
printf("%d", -mcmf());
return 0;
}
// LOJ6014.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 2e5 + 200, INF = 0x3f3f3f3f; int head[MAX_N], current, pre[MAX_N], dist[MAX_N]; int st, ed, flow[MAX_N], n, k, mx_range; bool vis[MAX_N]; vector<int> vec; struct segment { int l, r; } segs[MAX_N]; struct edge { int to, weight, cost, nxt; } edges[MAX_N << 1]; void addpath(int src, int dst, int weight, int cst) { edges[current].to = dst, edges[current].weight = weight; edges[current].cost = cst, edges[current].nxt = head[src]; head[src] = current++; } void addtube(int src, int dst, int weight, int cst) { addpath(src, dst, weight, cst); addpath(dst, src, 0, -cst); } bool bfs() { memset(dist, 0x3f, sizeof(dist)), memset(vis, false, sizeof(vis)); queue<int> q; q.push(st), vis[st] = true, flow[st] = INF, dist[st] = 0; while (!q.empty()) { int u = q.front(); vis[u] = false; q.pop(); for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].weight > 0 && dist[edges[i].to] > dist[u] + edges[i].cost) { dist[edges[i].to] = dist[u] + edges[i].cost; flow[edges[i].to] = min(flow[u], edges[i].weight); pre[edges[i].to] = i; if (!vis[edges[i].to]) vis[edges[i].to] = true, q.push(edges[i].to); } } return dist[ed] != INF; } int mcmf() { long long ans = 0; while (bfs()) { int p = ed, i = pre[p]; ans += 1LL * flow[ed] * dist[ed]; while (p != st) { edges[i].weight -= flow[ed], edges[i ^ 1].weight += flow[ed]; p = edges[i ^ 1].to, i = pre[p]; } } return ans; } int main() { memset(head, -1, sizeof(head)); scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%d%d", &segs[i].l, &segs[i].r); if (segs[i].l > segs[i].r) swap(segs[i].l, segs[i].r); vec.push_back(segs[i].l), vec.push_back(segs[i].r); } vec.push_back(-0x3f3f3f3f); sort(vec.begin(), vec.end()); st = 0, ed = 2 * n + 1; addtube(st, 1, k, 0); for (int i = 1; i < 2 * n; i++) addtube(i, i + 1, INF, 0); addtube(2 * n, ed, k, 0); for (int i = 1; i <= n; i++) { int len = segs[i].r - segs[i].l; segs[i].l = lower_bound(vec.begin(), vec.end(), segs[i].l) - vec.begin(); segs[i].r = lower_bound(vec.begin(), vec.end(), segs[i].r) - vec.begin(); addtube(segs[i].l, segs[i].r, 1, -len); } printf("%d", -mcmf()); return 0; }