BZOJ1672 Cleaning Shifts 清理牛棚
显然可以考虑 $dp$
设 $f[i]$ 表示当前到了时间 $i$,从初始到 $i$ 的时间都安排好打扫了
把所有牛按照区间 $l,r$ 双关键字排序
这样枚举到一头牛 $x$ 时,在 $x.l$ 之前的牛都考虑完了($x.l$ 是牛 $x$ 的左区间)
然后枚举 $[x.l-1,x.r]$ 之间的时间 $y$,有转移 $f[x.r]=min(f[x.r],f[y]+x.c)$ ($x.r$ 是牛 $x$ 的右区间,$x.c$ 是牛$x$ 的花费)
这样转移才能保证从开始时间一直到 $x.r$ 都有牛打扫
$x.l-1$ 是因为每头牛打扫的时间是闭区间,$[a,b]+[b+1,c]$ 的方案是合法的
然后这个东西的转移直接用线段树区间求 $min$ 和单点取 $min$ 就行了
具体看代码吧,注意区间可能为 $0$,写线段树的时候区间下标统一加一就行
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<set> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7; int n,S,E; ll T[N<<2],tag[N<<2]; inline void pushdown(int o,int l,int r) { if(!o||tag[o]==T[0]) return; T[o]=min(T[o],tag[o]); if(l==r) { tag[o]=T[0]; return; } tag[o<<1]=min(tag[o<<1],tag[o]); tag[o<<1|1]=min(tag[o<<1|1],tag[o]); tag[o]=T[0]; } int ql,qr; ll K,res; inline void change(int o,int l,int r) { pushdown(o,l,r); if(l>qr||r<ql) return; if(l>=ql&&r<=qr) { tag[o]=K; pushdown(o,l,r); return; } int mid=l+r>>1; change(o<<1,l,mid); change(o<<1|1,mid+1,r); T[o]=min(T[o<<1],T[o<<1|1]); } inline void query(int o,int l,int r) { pushdown(o,l,r); if(l>qr||r<ql) return; if(l>=ql&&r<=qr) { res=min(res,T[o]); pushdown(o,l,r); return; } int mid=l+r>>1; query(o<<1,l,mid); query(o<<1|1,mid+1,r); T[o]=min(T[o<<1],T[o<<1|1]); } struct dat{ int l,r,c; inline bool operator < (const dat &tmp) const { return l<tmp.l; } }d[N]; int main() { memset(T,0x3f,sizeof(T)); memset(tag,0x3f,sizeof(tag)); n=read(),S=read()+1,E=read()+1; for(int i=1,a,b,c;i<=n;i++) { a=read()+1,b=read()+1,c=read(); d[i]=(dat){a,b,c}; } sort(d+1,d+n+1); ql=d[1].r,qr=d[1].r,K=d[1].c; change(1,1,E); for(int i=2;i<=n;i++) { res=T[0]; ql=max(S,d[i].l-1); qr=d[i].r; query(1,1,E); if(res==T[0]) continue; K=res+d[i].c; ql=d[i].r; qr=d[i].r; change(1,1,E); } res=T[0]; ql=qr=E; query(1,1,E); if(res==T[0]) printf("-1\n"); else printf("%lld\n",res); return 0; }