Codeforces - Colonial Mansions

题目链接:Codeforces - Colonial Mansions


两个之间能否连通,只在于相互之间的差值。

我们用线段树维护差值即可,每个点的值是当前点和前一个点的差的绝对值。

然后二分找位置即可,注意细节。


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

你可能感兴趣的:(Codeforces,二分,线段树)