题面大意:
有N个线段,每个线段可以覆盖一段区间T1-T2 花费为S,求选出几个线段使得其完全覆盖M 到E 这一区间 并要求花费最少。
复杂度要求 nlog(E)。
这道题数据比较水,不要求离散化。考虑DP f[T2] = min(f[x]) +c {T1-1<=x<T2}
整个f数列可以用一颗线段树维护,维护最小值
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int maxn = 1e5+100;
struct node
{
int x,y;
long long z;
}T[maxn*4];
bool cmp(node a,node b)
{
return a.y < b.y;
}
int n,L,R,x,y,z;
long long f[maxn],mi[maxn*4];
void build(int rt,int l,int r)
{
if(l==r)
{
mi[rt]=f[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
mi[rt]=min(mi[ls],mi[rs]);
}
void update(int rt,int l,int r,int x,long long val)
{
if(l==r)
{
mi[rt]=val;
return ;
}
int mid=(l+r)>>1;
if(x<=mid) update(ls,l,mid,x,val);
else update(rs,mid+1,r,x,val);
mi[rt]=min(mi[ls],mi[rs]);
}
long long query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return mi[rt];
}
int mid=(l+r)>>1;
long long res=1e15;
if(L<=mid) res = min(res,query(ls,l,mid,L,R));
if(R>mid) res = min(res,query(rs,mid+1,r,L,R));
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>L>>R;
L+=2;R+=2;
memset(f,0x3f,sizeof(f));
memset(mi,0x3f,sizeof(mi));
for(int i=1;i<=n;i++)
{
cin>>T[i].x>>T[i].y>>T[i].z;
T[i].x+=2;T[i].y+=2;
}
sort(T+1,T+1+n,cmp);
f[L-1]=0;
build(1,1,R);
for(int i=1;i<=n;i++)
{
if(T[i].y>R) T[i].y = R;
if(T[i].x<L) T[i].x = L;
long long res = query(1,1,R,T[i].x-1,T[i].y-1);
f[T[i].y] = min(f[T[i].y],res+T[i].z);
update(1,1,R,T[i].y,f[T[i].y]);
}
if(f[R]>1e9) cout<<"-1"<<endl;
else cout<<f[R]<<endl;
return 0;
}
/*
3 0 4
0 2 3
3 4 2
0 0 1
*/