比较好的线段树二分.   

先考虑没有修改如何做:   

对于一个 $\mathrm{y}$, 先找到第一个可以选的 $\mathrm{a[i]}$, 然后尽量选这个连续段.   

显然,每当一个连续段停止时 $\mathrm{y}$ 的规模至少缩小了 $\mathrm{\frac{1}{2}}$.    

所以,连续段的个数不会超过 $\mathrm{log n}$.  

然后静态做的话这个东西直接在线段树上搜索一下就行.   

如果加上修改,就直接打 $\mathrm{lazy}$ 标记.   

直接查询的话会比较麻烦,可以将 $\mathrm{y}$ 增大前 $\mathrm{x-1}$ 的和强制从 $1$ 开始选.   



#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define N 200009
#define pb push_back
#define ll long long
#define ls now << 1
#define rs now << 1 | 1
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll sum[N<<2];
int n,Q,a[N],len[N<<2],lazy[N<<2],mi[N<<2];
void mark(int now, int v) {
lazy[now]=mi[now]=v;
sum[now] = 1ll * len[now] * v;
}
void pushdown(int now) {
if(lazy[now]) {
mark(ls, lazy[now]);
mark(rs, lazy[now]);
lazy[now] = 0;
}
}
void pushup(int now) {
mi[now] = min(mi[ls], mi[rs]);
sum[now] = sum[ls] + sum[rs];
}
void build(int l, int r, int now) {
len[now] = r - l + 1;
if(l == r) {
mi[now] = sum[now] = a[l];
return ;
}
int mid=(l+r)>>1;
build(l, mid, ls);
build(mid + 1, r, rs);
pushup(now);
}
void update(int l,int r,int now,int L,int R,int v) {
if(l>=L&&r<=R) {
mark(now, v);
return ;
}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid) update(l, mid, ls, L, R, v);
if(R>mid) update(mid + 1, r, rs, L, R, v);
pushup(now);
}
int query(int l, int r, int now, ll &v) {
if(v < mi[now]) return 0;
if(l == r) {
int d = 0;
if(sum[now] <= v) v -= sum[now], d = 1;
return d;
}
pushdown(now);
int mid=(l+r)>>1;
if(mi[ls] > v) return query(mid + 1, r, rs, v);
else {
if(sum[ls] <= v) {
v -= sum[ls];
return len[ls] + query(mid + 1, r, rs, v);
}
else {
int dl = query(l, mid, ls, v);
int dr = query(mid+1,r,rs, v);
return dl + dr;
}
}
}
// 第一个小于 v 的位置.
int search(int l,int r,int now,int v) {
if(l == r) {
return l;
}
pushdown(now);
int mid = (l + r) >> 1;
if(mi[ls] < v) return search(l, mid, ls, v);
else return search(mid + 1, r, rs, v);
}
ll get(int l,int r,int now,int L,int R) {
if(l >= L && r <= R) {
return sum[now];
}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid&&R>mid) {
return get(l,mid,ls,L,R)+get(mid+1,r,rs,L,R);
}
else if(L<=mid) return get(l,mid,ls,L,R);
else return get(mid+1,r,rs,L,R);
}
int main() {
// setIO("input");
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
}
build(1, n, 1);
for(int i=1;i<=Q;++i) {
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op == 1) {
// [1, x] 与 y 取 max.
if(mi[1] < y) {
int pos = search(1, n, 1, y);
if(pos <= x) {
update(1, n, 1, pos, x, y);
}
}
}
else {
ll o = 0;
if(x > 1) {
o = get(1, n, 1, 1, x - 1);
}
o += y;
printf("%d\n", query(1, n, 1, o) - (x - 1));
}
}
return 0;
}