@ysner
2018-09-27T19:36:42.000000Z
字数 2561
阅读 2255
线段树
DP
线段树优化DP
自治领
是一个猎人,他准备打猎,他站在平面直角坐标系的位置。
天上有只小鸟从右往左以的速度水平飞过,每只小鸟都是一条水平方向的线段。
由于枪法不太好,他只会竖直向上开枪,此时与轴有交(包括端点)的小鸟都会被击中并成为的猎物。
在开完一枪后需要秒来装弹,在此期间不能再次开枪。
你需要求出最多能得到多少只猎物。
很容易能想到一个方程式:
设表示当时间进行到时刻,并且这时打一枪,最多总共获得多少猎物。
设表示在时间打一枪能获得多少收益。
设表示与中包含猎物的重复个数。
则
看起来那个相当难求,因为每转移一次,都要维护转移到的猎物,还要去重,复杂度很危险。
其实不妨这么想,可以用差分求出所有。同时出现在、的线段,就是在中出现后,到时没有被删除的线段。
我们可以在更新的值时,在线段树上将其更新为:在出的边,这样每当一条线段终结时,在线段树上给这条线段区间加一即可。
这样在到时刻时,的值就是。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
#define ll long long
#define re register
#define il inline
#define ls x<<1
#define rs x<<1|1
#define pb(a) push_back(a)
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e5+100;
struct dat
{
int l,r;
il bool operator < (const dat &o) const
{
if(r==o.r) return l<o.l;
return r<o.r;
}
}a[N];
int n,m,k,tot,cha[N],in[N],mx,p=1,ans,now,t[N<<2],tag[N<<2],f[N];
il int gi()
{
re int x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void upd(re int x){t[x]=max(t[ls],t[rs]);}
il void cover(re int x,re int w){t[x]+=w;tag[x]+=w;}
il void Pushdown(re int x){cover(ls,tag[x]);cover(rs,tag[x]);tag[x]=0;}
il void Modify(re int x,re int l,re int r,re int pos,re int w)
{
if(l==r) {t[x]=w;return;}
re int mid=l+r>>1;
if(tag[x]) Pushdown(x);
if(pos<=mid) Modify(ls,l,mid,pos,w);
else Modify(rs,mid+1,r,pos,w);
upd(x);
}
il void Modify(re int x,re int l,re int r,re int ql,re int qr,re int w)
{
if(ql<=l&&r<=qr) {cover(x,w);return;}
re int mid=l+r>>1;
if(tag[x]) Pushdown(x);
if(ql<=mid) Modify(ls,l,mid,ql,qr,w);
if(qr>mid) Modify(rs,mid+1,r,ql,qr,w);
upd(x);
}
il int Query(re int x,re int l,re int r,re int ql,re int qr)
{
if(ql<=l&&r<=qr) return t[x];
re int mid=l+r>>1;
if(tag[x]) Pushdown(x);
if(qr<=mid) return Query(ls,l,mid,ql,qr);
if(ql>mid) return Query(rs,mid+1,r,ql,qr);
return max(Query(ls,l,mid,ql,qr),Query(rs,mid+1,r,ql,qr));
}
int main()
{
freopen("bird.in","r",stdin);
freopen("bird.out","w",stdout);
n=gi();k=gi();
fp(i,1,n)
{
re int l=max(0,gi()),r=gi();
if(r<0) continue;++l;++r;
a[++tot]=(dat){l,r};
++cha[l];++in[l];--cha[r+1];mx=max(mx,r+1);
}
sort(a+1,a+1+tot);
fp(i,1,mx) cha[i]+=cha[i-1];
fp(i,1,mx)
{
f[i]=cha[i]+Query(1,0,mx,max(0,i-2*k),max(0,i-k));
ans=max(ans,f[i]);now+=in[i];
Modify(1,0,mx,i,f[i]-now);
while(p<=tot&&a[p].r==i)
{
--now;
Modify(1,0,mx,a[p].l,a[p].r,1);
++p;
}
}
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}