34 ACwing 295 Cleaning Shifts 题解
Cleaning Shifts
题面
农夫约翰雇佣他的 N 头奶牛帮他进行牛棚的清理工作。
他将全天分为了很多个班次,其中第 M 个班次到第 E 个班次(包括这两个班次)之间必须都有牛进行清理。
这 N 头牛中,第 i 头牛可以从第 ai 个班次工作到第 bi 个班次,同时,它会索取 ci 的佣金。
请你安排一个合理的清理班次,使得 [M,E] 时间段内都有奶牛在清理,并且所需支付给奶牛的报酬最少。
1 ≤ N ≤ 10000,
0 ≤ M,E ≤ 86399,
M ≤ ai ≤ bi ≤ E,
0 ≤ ci ≤ 500000
题解
设 \(f(i)\) 表示只用 \(i\) 左边的区间 \([M,i]\) 都有牛打扫的最小代价,初始 \(f(M - 1) = 0\) ,目标为 \(f(E)\)
初始先按照 \(b_i\) 从小到大排序,然后一个一个转移,保证无后效性
有转移 \(f(b_i) = \min_{a_i - 1 \le j < b_i} \{ f(j) \} + c_i\)
用线段树来维护 \(f\) ,可以在 \(O(\log n)\) 内实现区间查询最小值以及单点修改,总时间复杂度为 \(O(n \log n)\)
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const ll INF = 4e18;
int n, L, R;
struct Cow {
int l, r, c;
bool operator < (const Cow &t) const {
return r < t.r;
}
} a[N];
struct Segment {
#define ls (p << 1)
#define rs (p << 1 | 1)
ll val[N << 2];
void update (int p) {
val[p] = min (val[ls], val[rs]);
}
void build (int p, int l, int r) {
val[p] = INF;
if (l == r) return;
int mid = (l + r) >> 1;
build (ls, l, mid);
build (rs, mid + 1, r);
}
void modify (int p, int l, int r, int pos, ll d) {
if (l == r) {
val[p] = min (val[p], d);
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) modify (ls, l, mid, pos, d);
else modify (rs, mid + 1, r, pos, d);
update (p);
}
ll query (int p, int l, int r, int x, int y) {
if (x <= l && r <= y) {
return val[p];
}
int mid = (l + r) >> 1;
ll res = INF;
if (x <= mid) res = min (res, query (ls, l, mid, x, y));
if (mid < y) res = min (res, query (rs, mid + 1, r, x, y));
return res;
}
} Tr;
int main () {
cin >> n >> L >> R;
for (int i = 1; i <= n; i ++) {
cin >> a[i].l >> a[i].r >> a[i].c;
}
sort (a + 1, a + 1 + n);
Tr.build (1, L - 1, R);
Tr.modify (1, L - 1, R, L - 1, 0);
for (int i = 1; i <= n; i ++) {
ll res = Tr.query (1, L - 1, R, a[i].l - 1, a[i].r - 1) + a[i].c;
Tr.modify (1, L - 1, R, a[i].r, res);
}
ll res = Tr.query (1, L - 1, R, R, R);
if (res == INF) cout << -1 << endl;
else cout << res << endl;
return 0;
}