35分线段树维护最左右负数位置思路求调
查看原帖
35分线段树维护最左右负数位置思路求调
231946
CuSO4_and_5H2O楼主2022/10/4 09:07

RT

思路是维护一个区间最左/右的负数位置然后计算出每个区间里的乘积总和

#include<bits/stdc++.h>
#define int long long
#define max(A,B) (A<B?B:A)
#define min(A,B) (A>B?B:A)
#define bug cout<<"I AK IOI"<<endl;
#define lf bh<<1
#define re bh<<1|1
using namespace std;
const int N=2e5+1,P=1073741825;

int n,m;
struct node{
	int sum,l,r; 
	//sum是区间总和,l是这个区间里最左的负数,r是最右边的 
}t[N*4];

void push_on(int bh)
{
	t[bh].l=min(t[lf].l,t[re].l);
	t[bh].r=max(t[lf].r,t[re].r);
	t[bh].sum=t[lf].sum*t[re].sum;
	if(t[bh].sum>=P) t[bh].sum=P;
}

void built(int bh,int l,int r)
{
	if(l==r){
		int a;
		cin>>a;
		t[bh].sum=a;
		t[bh].l=(t[bh].sum<0?l:1e9);
		t[bh].r=(t[bh].sum<0?l:-1e9);
		return ;
	}
	int mid=(l+r)>>1;
	built(lf,l,mid),built(re,mid+1,r);
	push_on(bh);
}

void change(int bh,int l,int r,int x,int a)
{
	if(l==r){
		t[bh].sum=a;
		t[bh].l=(t[bh].sum<0?l:1e9);
		t[bh].r=(t[bh].sum<0?l:-1e9);
		return ;
	}
	int mid=(l+r)>>1;
	if(mid>=x) change(lf,l,mid,x,a);
	else change(re,mid+1,r,x,a);
	push_on(bh);
}

int cxl(int bh,int l,int r,int fx,int fy)//查询一个区间的最左边的负数的位置 
{
	if(fx<=l && fy>=r) return t[bh].l;
	int mid=(l+r)>>1;
	if(mid>=fy) return cxl(lf,l,mid,fx,fy);
	if(mid<fx) return cxl(re,mid+1,r,fx,fy);
	return min(cxl(lf,l,mid,fx,fy),cxl(re,mid+1,r,fx,fy));
}
int cxr(int bh,int l,int r,int fx,int fy)//最右边负数的位置 
{
	if(fx<=l && fy>=r) return t[bh].r;
	int mid=(l+r)>>1;
	if(mid>=fy) return cxr(lf,l,mid,fx,fy);
	if(mid<fx) return cxr(re,mid+1,r,fx,fy);
	return max(cxr(lf,l,mid,fx,fy),cxr(re,mid+1,r,fx,fy));
}

int cx(int bh,int l,int r,int fx,int fy)//查询区间乘积和 
{
	if(fx>fy) return 1;
	if(fx<=l && fy>=r){
		return t[bh].sum;
	}
	int mid=(l+r)>>1;
	int L=1,R=1;
	if(mid>=fy) L=cx(lf,l,mid,fx,fy);
	else if(mid<fx)  R=cx(re,mid+1,r,fx,fy);
	else L=cx(lf,l,mid,fx,fy),R=cx(re,mid+1,r,fx,fy);
	int ans=L*R;
	if(ans>=P) return P;
	return ans;
}

int _cx(int l,int r)
{
	int ans=cx(1,1,n,l,r);
	if(ans<0){//如果是负数的话 
		if(l==r) return 1;//如果只有一个数那他怎么选也是负数就输出 
		int L=cxl(1,1,n,l,r),R=cxr(1,1,n,l,r);//求出最左/右的负数 
		return max(cx(1,1,n,l,R-1),cx(1,1,n,L+1,r));//查询最大值 
	}
	return ans;
}

signed main(){
	cin>>n>>m;
	built(1,1,n);
	for(int i=1,bj,l,r;i<=m;i++)
	{
		cin>>bj>>l>>r;
		if(bj==1) change(1,1,n,l,r);
		else {
			int ans=_cx(l,r);
			if(ans>=P) cout<<"Too large"<<endl;
			else cout<<ans<<endl;
		}
	}
}

2022/10/4 09:07
加载中...