E - Greedy Shopping(区间覆盖,区间查询)

题意

给n,m两个数字,表示 n长度数组a 和 m个操作,数组a有一个特点,从大到小

每个操作输入t x y

当t==1时候,操作1->把[1,x]区间 max(a[],y);

当t==2时候,操作2->把[x,n]区间 从x到n遍历,如果有比y小的,y减掉a[i],个数加一,然后输出可以买多少个

就比如数组:
10 10 7 6 1
操作:
t=2,x=1,y=17
取第一个和第三个
输出2

思路

一看就是线段树,然后因为操作二的限制,数组一定是从大到小的,那么我们判断区间最小值,最大值和区间和

操作一,我们可以用最大值来判断是否需要lazy标记

操作二,我们可以用递归,先递归左子树上的区间和有没有比y小,然后在递归右子树有没有比y小的

区间最大值和区间和都有用,区间最小值呢?

答案就是用来优化,如果你遇到y的值比区间最小值还要小,直接return了

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define lowbit(x) x&-x
using namespace std;
const int N=2e5+100;
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans*=a;ans%=mod;
        }
        a*=a;a%=mod;
        b>>=1;
    }
    return ans;
}
int t,n,m;
int tr[N<<2],lazy[N<<2],ge[N<<2],a[N],mi[N<<2];
ll sum[N<<2];
void pushup(int x){
    tr[x]=max(tr[x<<1],tr[x<<1|1]);
    mi[x]=min(mi[x<<1],mi[x<<1|1]);
    sum[x]=sum[x<<1]+sum[x<<1|1];
}
void pushdown(int x,int l,int r){
    if(lazy[x]){
        if(l==r){
            sum[x]=lazy[x];
            tr[x]=lazy[x];mi[x]=lazy[x];
            lazy[x]=0;
        }
        else{
            lazy[x<<1]=lazy[x];lazy[x<<1|1]=lazy[x];
            tr[x<<1]=mi[x<<1]=lazy[x];
            int mid=(l+r)>>1;
            sum[x<<1]=(ll)tr[x<<1]*(mid-l+1);
            tr[x<<1|1]=mi[x<<1|1]=lazy[x];
            sum[x<<1|1]=(ll)tr[x<<1|1]*(r-mid);
            lazy[x]=0;
        }
    }
}
void build(int x,int l,int r){
    lazy[x]=0;
    if(l==r){
        tr[x]=a[l];sum[x]=(ll)a[l];mi[x]=a[l];return;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
void update(int x,int l,int r,int L,int R,int zhi){
    if(mi[x]>zhi){return;}
    if(L<=l && r<=R && tr[x]<=zhi){
        pushdown(x,l,r);
        lazy[x]=zhi;
        sum[x]=(ll)zhi*(r-l+1);
        tr[x]=zhi;mi[x]=zhi;
        return;
    }
    pushdown(x,l,r);
    int mid=(l+r)>>1;
    if(mid>=L){
        update(x<<1,l,mid,L,R,zhi);
    }
    if(R>mid){
        update(x<<1|1,mid+1,r,L,R,zhi);
    }
    pushup(x);
}
ll ans;
int g=0;
void querry(int x,int l,int r,int L,int R){
      if(mi[x]>ans){return;}
     if(L<=l && r<=R && sum[x]<=ans){
        pushdown(x,l,r);
        ans-=sum[x];g+=(r-l+1);//cout<<sum[x]<<endl;
        return;
     }
     pushdown(x,l,r);
     int mid=(l+r)>>1;

     if(mid>=L){
         querry(x<<1,l,mid,L,R);
     }
     if(R>mid){
         querry(x<<1|1,mid+1,r,L,R);
     }
     pushup(x);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=0;i<m;i++){
        int x;scanf("%d",&x);//cout<<sum[1]<<endl;
        if(x==1){
            int r,zhi;
            scanf("%d%d",&r,&zhi);
            update(1,1,n,1,r,zhi);
        }
        else{
            int l;
            scanf("%d%lld",&l,&ans);
            g=0;querry(1,1,n,l,n);
            printf("%d\n",g);
        }
    }
    return 0;
}
/*
*/
posted @ 2020-11-27 16:23  ouluy  阅读(160)  评论(0编辑  收藏  举报