【链接】http://poj.org/problem?id=3171
【题意】有N个贴纸,可覆盖范围为[ai,bi],售价ci,问要覆盖L,R,区间,最少需要多少代价
【分析】
dp[i]代表覆盖区间[L,i]的最小花费。
将所有贴纸按右端点排序,设当前贴纸为[ai,bi],价格ci,状态转移方程为:
dp[i]=min{f[x]}+ci (ai-1<=x<bi)
【初值】dp[L-1]=0;其余为inf
【目标】min(f[bi])(bi>=R)
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 1e6+5;
const int inf = 0x3f3f3f3f;
ll dp[maxn];
struct node {int l, r;ll cost;}t[maxn];
int cmp(node a, node b) {return a.r < b.r;}
struct tree {
int l, r, num;
ll min;
}tr[maxn<<2];
void build(int p, int l, int r) {
tr[p].l = l;
tr[p].r = r;
tr[p].min = inf;
if (l == r)return;
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
}
void update(int p, int id, ll val) {
if (tr[p].l == tr[p].r) {
tr[p].min = min(tr[p].min, val);
return;
}
int mid = (tr[p].l + tr[p].r) >> 1;
if (id <= mid) update(p << 1, id, val);
else update(p << 1 | 1, id, val);
tr[p].min = min(tr[p << 1].min, tr[p << 1 | 1].min);
}
ll query(int p, int l, int r) {
if (tr[p].l >= l && tr[p].r <= r) return tr[p].min;
int mid = (tr[p].l + tr[p].r) >> 1;
if (r <= mid)return query(p << 1, l, r);
else if(l>mid)return query(p << 1 | 1, l, r);
else return min(query(p << 1, l, r), query(p << 1 | 1, l, r));
}
int main() {
int n, l,r;
int f = 0;
scanf("%d%d%d", &n, &l, &r);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &t[i].l, &t[i].r, &t[i].cost);
}
sort(t + 1, t + 1 + n, cmp);
build(1, 1, r + 1);
memset(dp, inf, sizeof(dp));
for (int i = 1; i <= n; i++) {
if (t[i].r < l)continue;
if (t[i].l <= l) {
dp[t[i].r] = min(dp[t[i].r], t[i].cost);
}
else {
dp[t[i].r] = min(dp[t[i].r], query(1, t[i].l, t[i].r) + t[i].cost);
}
update(1, t[i].r + 1, dp[t[i].r]);
}
ll ans = inf;
for (int i = r; i <= t[n].r; i++) {
ans = min(ans, dp[i]);
}
if (ans >= inf) {
printf("-1\n");
}
else printf("%lld\n", ans);
}