bird

这个题其实挺好的(除了条件没给清)

题解

最显然的dp,f[i]表示在i打了一枪最多得到多少只鸟,$f[i]=\sum\limits_{j=1}^{j<=i-k}f[j]+cnt[i]$然而如果一只鸟长度跨越几次开枪一只鸟会被重复算很多次,比如1秒开次枪,鸟100000长度,会多算

所以实际dp应该是$f[i]=\sum\limits_{j=1}^{j<=i-k} f[j]+cnt[i]-chongfu$,

可以利用差分思想,假设一只鸟覆盖[l,r],在鸟来之前[l,r]-1鸟走之后[l,r]+1,每多算一次[l,r]区间的鸟,也会被多减一次1,最后统一给[l,r]+1就得到了实际的值!

用线段树维护区间+,-,区间max,set维护每只鸟即可

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 2001101
struct tree{
    ll l,r,maxx,f;
}tr[A];
struct node{
    ll l,r;
    node(){}
    node(const ll &a,const ll &b){
        l=a,r=b;
    }
    friend bool operator < (const node &a,const node &b){
        return a.r<b.r;
    }
}qujian[A];
ll cmp(const node &a,const node &b){
    return a.l<b.l;
}
multiset<node> st;
multiset<node> :: iterator it;
ll maxx,tot,k,n,mx,ans;
ll cnt[A],in[A],f[A];
void built(ll x,ll l,ll r){
    tr[x].l=l,tr[x].r=r;
    if(l==r){
        return ;
    }
    ll mid=(tr[x].l+tr[x].r)>>1;
    built(x<<1,l,mid);
    built(x<<1|1,mid+1,r);
}
void up(ll x){
    tr[x].maxx=max(tr[x<<1].maxx,tr[x<<1|1].maxx);
}
void down(ll x){
    tr[x<<1].maxx+=tr[x].f;
    tr[x<<1|1].maxx+=tr[x].f;
    tr[x<<1].f+=tr[x].f;
    tr[x<<1|1].f+=tr[x].f;
    tr[x].f=0;
}
void seg_add(ll x,ll l,ll r,ll d){
//    printf("l=%lld r=%lld tr[x].l=%lld .r=%lld\n",l,r,tr[x].l,tr[x].r);
    if(tr[x].l>=l&&tr[x].r<=r){
        tr[x].maxx+=d;
        tr[x].f+=d;
        return ;
    }
    if(tr[x].f) down(x);
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(mid>=l) seg_add(x<<1,l,r,d);
    if(mid<r) seg_add(x<<1|1,l,r,d);
    up(x);
}
void seg_max(ll x,ll l,ll r){
    if(l>r) return ;
//    printf("tr[x].l=%lld r=%lld l=%lld r=%lld\n",tr[x].l,tr[x].r,l,r);
    if(tr[x].l>=l&&tr[x].r<=r){
        maxx=max(maxx,tr[x].maxx);
        return ;
    }
    if(tr[x].f) down(x);
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(mid>=l) seg_max(x<<1,l,r);
    if(mid<r) seg_max(x<<1|1,l,r);
    up(x);
}
void insert(ll x,ll pla,ll val){
//    printf("***l=%lld r=%lld pla=%lld val=%lld\n",tr[x].l,tr[x].r,pla,val);
    if(tr[x].l==tr[x].r){
        tr[x].maxx+=val;
        return ;
    }
    if(tr[x].f) down(x);
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(mid>=pla) insert(x<<1,pla,val);
    else insert(x<<1|1,pla,val);
    up(x);
}
void print(ll x){
    printf("l=%lld r=%lld f=%lld maxx=%lld\n",tr[x].l,tr[x].r,tr[x].f,tr[x].maxx);
    if(tr[x].l==tr[x].r) return ;
    print(x<<1),print(x<<1|1);
}
int main(){
//    freopen("da.in","r",stdin);
//    freopen("ans.sol","w",stdout);
    scanf("%lld%lld",&n,&k);
    for(ll i=1;i<=n;i++){
        ll l,r;
        scanf("%lld%lld",&l,&r);
        if(r<0) continue ;
        l=max(0ll,l);
        qujian[++tot]=node(l,r);
        mx=max(mx,r);
        cnt[l]++,cnt[r+1]--;
        in[l]++;
    }
    for(ll i=1;i<=mx;i++)
        cnt[i]+=cnt[i-1];
    built(1,0,mx);
    sort(qujian+1,qujian+tot+1,cmp);
    ll ita=1,now=0;
    for(ll i=0;i<=mx;i++){
//        printf("i=%lld\n",i);
        while(qujian[ita].l==i){
            st.insert(qujian[ita]);
            ita++;now++;
        }
        maxx=0;
        seg_max(1,0,i-k);
        maxx+=cnt[i];
        ans=max(ans,maxx);
//        printf("***maxn=%lld\n",maxx);
        insert(1,i,maxx-now);
        it=st.lower_bound(node(0,0));
        while(it!=st.end()&&it->r<=i){
            ll l=it->l,r=it->r;
            node tmp=*it;
            seg_add(1,l,r,1);
            it++;
            now--;
            st.erase(tmp);
        }
//        print(1);
    }
    printf("%lld\n",ans);
}
View Code

猜你喜欢

转载自www.cnblogs.com/znsbc-13/p/11741704.html