传送门
本题需要知道一个结论,就是操作二找值的时候其实最多只会跳
O
(
l
o
g
(
n
)
)
O(log(n))
O(log(n))段,这样的话我们可以用线段树去二分查找那些符合条件的段。
具体来说,对于操作一,我们每次找到恰好满足小于
y
y
y的一个点
i
i
i,然后修改
i
∼
x
i\sim x
i∼x段的值为
y
y
y,线段树打懒标记的操作不多说了。
对于操作二,我们用
w
h
i
l
e
while
while处理,假设现在位于
c
u
r
cur
cur位置,每次都线段树二分找到前缀和小于等于
y
+
s
u
m
[
1
∼
c
u
r
−
1
]
y+sum[1\sim cur-1]
y+sum[1∼cur−1]的最大位置,假设是
p
p
p位置,那么我们直接跳到
p
+
1
p+1
p+1,同时统计答案,改变
y
y
y即可,直到没办法往下跳(
y
y
y太小)或者跳到终点为止。
int n,q,a[maxn],mi[maxn<<2],lz[maxn<<2];
ll t[maxn<<2];
void pushup(int rt){
t[rt]=t[rt<<1]+t[rt<<1|1];
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void pushdown(int rt,int l,int r){
if(lz[rt]){
int mid=l+r>>1;
lz[rt<<1]=lz[rt<<1|1]=mi[rt<<1]=mi[rt<<1|1]=lz[rt];
t[rt<<1]=1ll*lz[rt]*(mid-l+1);
t[rt<<1|1]=1ll*lz[rt]*(r-mid);
lz[rt]=0;
}
}
void build(int rt,int l,int r){
if(l==r){
t[rt]=mi[rt]=a[l];
return;
}
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void cg(int rt,int l,int r,int ql,int qr,int x){//区间打懒标记
if(ql<=l && r<=qr){
lz[rt]=x;
t[rt]=1ll*x*(r-l+1);
mi[rt]=x;
return;
}
pushdown(rt,l,r);
int mid=l+r>>1;
if(ql<=mid && qr>=l)cg(rt<<1,l,mid,ql,qr,x);
if(ql<=r && qr>=mid+1)cg(rt<<1|1,mid+1,r,ql,qr,x);
pushup(rt);
}
int qry(int rt,int l,int r,int ql,int qr,int x){//查找[ql,qr]中小于等于x的最左点
if(l==r){
if(t[rt]<=x)return l;
return inf;
}
int mid=l+r>>1,ans=inf;
pushdown(rt,l,r);
if(ql<=mid && qr>=l && mi[rt<<1]<=x)ans=qry(rt<<1,l,mid,ql,qr,x);
if(ql<=r && qr>=mid+1 && mi[rt<<1|1]<=x && ans==inf)ans=qry(rt<<1|1,mid+1,r,ql,qr,x);
pushup(rt);
return ans;
}
ll getsum(int rt,int l,int r,int ql,int qr){//返回[ql,qr]的和
if(ql>qr)return 0;
if(ql<=l && r<=qr)return t[rt];
int mid=l+r>>1;ll ans=0;
pushdown(rt,l,r);
if(ql<=mid && qr>=l)ans+=getsum(rt<<1,l,mid,ql,qr);
if(ql<=r && qr>=mid+1)ans+=getsum(rt<<1|1,mid+1,r,ql,qr);
pushup(rt);
return ans;
}
int find_sum(int rt,int l,int r,ll x){//查找前缀和小于等于x的最右点
if(l==r){
if(t[rt]<=x)return l;
return l-1;
}
int mid=l+r>>1;int ans=0;
pushdown(rt,l,r);
if(t[rt<<1]<x)ans=find_sum(rt<<1|1,mid+1,r,x-t[rt<<1]);
else ans=find_sum(rt<<1,l,mid,x);
pushup(rt);
return ans;
}
int main(){
n=rd(),q=rd();
FOR(i,1,n+1)a[i]=rd();
build(1,1,n);
while(q--){
int op=rd(),x=rd(),y=rd();
if(op==1){
int l=qry(1,1,n,1,x,y);
if(l!=inf)cg(1,1,n,l,x,y);
}else{
int ans=0;
while(x<=n && y){
int l=qry(1,1,n,x,n,y);
if(l==inf)break;
ll sum=getsum(1,1,n,1,l-1);
sum+=y;
int r=find_sum(1,1,n,sum);
if(r<=l-1)break;
ans+=r-l+1;
y=sum-getsum(1,1,n,1,r);
x=r+1;
}
wrn(ans);
}
}
}