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;
}
/*
*/