题解 P4644 【[Usaco2005 Dec]Cleaning Shifts 清理牛棚】
线段树维护优化DP 裸题。
首先,题目变量名取得十分奇特,所以我们约定:开始时间由M变为B,每个奶牛的花费由S变为cost,时间段总长为L
另外,文中的|是集合的符号不是 or 运算哈
按照普通的
然后我们发现,每个时间段都扫一遍性价比是很低的,因为如果我们不更新
显然,这个
然后就
代码细节&解释
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MN 25005
#define INF 2147483647777
#define Ls (nod<<1)
#define Rs (nod<<1|1)
#define mid ((l+r)>>1)
struct data{
int t1,t2,cost;
}w[MN];
int n,b,e;
LL f[MN<<4],ans[MN<<2];
//f:线段树中的答案 ans:从L到i的答案
inline LL min(int a,int b){
return a<b?a:b;
}
inline bool cmp(data a,data b){
return a.t2<b.t2;
}
inline int read(){
int a=0;
char c=getchar();
while(c>57||c<48) c=getchar();
while(47<c&&c<58){
a=a*10+c-48;
c=getchar();
}
return a;
}//快读
void build(int nod,int l,int r){
f[nod]=INF;
if(l==r)return;
build(Ls,l,mid);
build(Rs,mid+1,r);
}//建树
LL ask(int nod,int l,int r,int b,int e){
if(l>e||r<b)return INF;
if((b<=l&&r<=e)||l==r) return f[nod];
return min(ask(Ls,l,mid,b,e),ask(Rs,mid+1,r,b,e));
}//最小值
void pushup(int nod,int l,int r,int loc){
if(l>loc||r<loc) return;
if(l==r) {f[nod]=ans[loc];return;}
pushup(Ls,l,mid,loc);
pushup(Rs,mid+1,r,loc);
f[nod]=min(f[Ls],f[Rs]);
}//修改
int main(){
n=read();b=read();e=read();
for(int i=1;i<=n;++i){
w[i].t1=read();
w[i].t2=read();
w[i].cost=read();
}
build(1,b,e);
sort(w+1,w+1+n,cmp);//按t2排序,更新完前面再更新后面
for(int i=b;i<=e;++i)ans[i]=INF;
for(int i=1;i<=n;++i){
int temp=ans[w[i].t2];
ans[w[i].t2]=min(ans[w[i].t2],((w[i].t1>b)?ask(1,b,e,w[i].t1-1,w[i].t2):0)+(LL)w[i].cost);//这里要注意,当t1为b时要特判
if(temp!=ans[w[i].t2])pushup(1,b,e,w[i].t2);
}
ans[e]!=INF?printf("%lld",ans[e]):puts("-1");
return 0;
}