两个之间能否连通,只在于相互之间的差值。
我们用线段树维护差值即可,每个点的值是当前点和前一个点的差的绝对值。
然后二分找位置即可,注意细节。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=1e5+10;
int n,q,h[N],mx[N<<2];
inline void push_up(int p){mx[p]=max(mx[p<<1],mx[p<<1|1]);}
void change(int p,int l,int r,int x){
if(l==r){mx[p]=abs(h[x]-h[x-1]); return ;}
int mid=l+r>>1;
if(x<=mid) change(p<<1,l,mid,x);
else change(p<<1|1,mid+1,r,x);
push_up(p);
}
int ask(int p,int l,int r,int ql,int qr){
if(l==ql&&r==qr) return mx[p];
int mid=l+r>>1;
if(qr<=mid) return ask(p<<1,l,mid,ql,qr);
else if(ql>mid) return ask(p<<1|1,mid+1,r,ql,qr);
else return max(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
}
inline int askl(int x,int y){
int l=1,r=x;
while(l<r){
int mid=l+r>>1;
if(ask(1,1,n,mid,x)<=y) r=mid;
else l=mid+1;
}
return l-1;
}
inline int askr(int x,int y){
int l=x+1,r=n;
while(l<r){
int mid=l+r+1>>1;
if(ask(1,1,n,x+1,mid)<=y) l=mid;
else r=mid-1;
}
return l;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>q; h[0]=-1e9-10;
for(int i=1;i<=n;i++) cin>>h[i];
for(int i=1;i<=n;i++) change(1,1,n,i);
for(int i=1,op,x,y,l,r;i<=q;i++){
cin>>op>>x>>y;
if(op==1){
h[x]=y,change(1,1,n,x);
if(x!=n) change(1,1,n,x+1);
}else{
if(x==1||abs(h[x]-h[x-1])>y) l=x;
else l=askl(x,y);
if(x==n||abs(h[x]-h[x+1])>y) r=x;
else r=askr(x,y);
cout<<r-l+1<<'\n';
}
}
return 0;
}