优美的线段树优化dp.
先将所有线段按右端点递增排序.
设f[i]表示清理到i的最小花费(不可能则为无穷大)
那么对于每一条线段,有如下转移:
$$f[b_i]=min(f[b_i],min _{j=a_i-1}^{b_i} f[j]+1)$$
直接暴力做时间复杂度是$O(n^2)$
而显然查询的$min_{j=a_i-1}^{b_i} f[j]+1$是区间最值,用单点修改,区间求最值的线段树维护一下就好了.
时间复杂度$O(nlogn)$
/**********/
#define MAXN 1000011
ll n,t,end;
struct Segment_Tree//线段树
{
ll t[MAXN<<2|1];
#define rt t[num]
#define tl t[num<<1]
#define tr t[num<<1|1]
void pushup(un num)
{
rt=min(tl,tr);
}
void build(un l=0,un r=end,un num=1)//初始化为无穷大
{
if(l==r)
{
rt=INF;
return;
}
un mid=(l+r)>>1;
build(l,mid,num<<1);build(mid+1,r,num<<1|1);
pushup(num);
}
void modify(un p,ll val,un l=0,un r=end,un num=1)
{
if(l==r)
{
if(l==p)rt=val;
return;
}
un mid=(l+r)>>1;
if(p<=mid)modify(p,val,l,mid,num<<1);
else modify(p,val,mid+1,r,num<<1|1);
pushup(num);
}
ll Qmin(un ql,un qr,un l=0,un r=end,un num=1)
{
if(ql<=l&&r<=qr)return rt;
ll ans=INF;
un mid=(l+r)>>1;
if(ql<=mid)umin(ans,Qmin(ql,qr,l,mid,num<<1));
if(qr>mid)umin(ans,Qmin(ql,qr,mid+1,r,num<<1|1));
return ans;
}
}sgt;
struct Seg//线段
{
ll l,r;
bool operator <(const Seg& t)
const
{
return r<t.r;
}
}a[MAXN];
int main()
{
n=read(),t=read();
for(ll i=1;i<=n;++i)
{
a[i].l=read(),a[i].r=read();
}
std::sort(a+1,a+n+1);
end=t;
sgt.build();
sgt.modify(0,0);
for(ll i=1;i<=n;++i)
{
ll minv=min(sgt.Qmin(a[i].l-1,a[i].r)+1,sgt.Qmin(a[i].r,a[i].r));//线段树优化的dp
sgt.modify(a[i].r,minv);
}
ll ans=sgt.Qmin(t,t);
printf("%lld",ans==INF?-1:ans);
return 0;
}