线段树——区间修改+查询(当前/历史)最大值模板

线段树的区间修改加查询区间最大值相信大家都熟悉了,但是,如何查询一个历史的最大值呢?
此模板单纯是自己写写的,在oj上没有找到,是bzoj3064的弱化版,那题还有一个区间赋值的操作,更加麻烦。
#include 
using namespace std;
const int N=1e5+5;
int n,m,x,y,v;
int a[N];
char str[10];
struct node{int sum,max,tagsum,tagmax;}T[N<<2];

inline void pushdown(int k)
{
	//由于T[k].max,T[k].sum的不断更新,所以这边要使用T[k].tagmax,T[k].tagsum 
	T[k<<1].max=max(T[k<<1].max,T[k<<1].sum+T[k].tagmax);
	T[k<<1].sum+=T[k].tagsum;
	T[k<<1].tagmax=max(T[k<<1].tagmax,T[k<<1].tagsum+T[k].tagmax);
	T[k<<1].tagsum+=T[k].tagsum; 
	
	T[k<<1|1].max=max(T[k<<1|1].max,T[k<<1|1].sum+T[k].tagmax);
	T[k<<1|1].sum+=T[k].tagsum;
	T[k<<1|1].tagmax=max(T[k<<1|1].tagmax,T[k<<1|1].tagsum+T[k].tagmax);
	T[k<<1|1].tagsum+=T[k].tagsum; 
	
	T[k].tagsum=0; T[k].tagmax=-2e9;
}

void change(int k,int l,int r,int qx,int qy,int v)
{
	if (qx<=l && r<=qy)
	{
		T[k].sum+=v;
		T[k].max=max(T[k].max,T[k].sum);
		T[k].tagsum+=v;
		T[k].tagmax=max(T[k].tagmax,T[k].tagsum); 
		return;
	}
	pushdown(k);
	int mid=l+r>>1;
	if (qx<=mid) change(k<<1,l,mid,qx,qy,v);
	if (mid<qy) change(k<<1|1,mid+1,r,qx,qy,v);
	T[k].sum=max(T[k<<1].sum,T[k<<1|1].sum);
	T[k].max=max(T[k<<1].max,T[k<<1|1].max);
}

int query(int k,int l,int r,int qx,int qy)
{
	if (qx<=l && r<=qy) return T[k].max;
	pushdown(k);
	int mid=l+r>>1;
	int res=-2e9;
	if (qx<=mid) res=max(res,query(k<<1,l,mid,qx,qy));
	if (mid<qy) res=max(res,query(k<<1|1,mid+1,r,qx,qy));
	return res;
}

int querynow(int k,int l,int r,int qx,int qy)
{
	if (qx<=l && r<=qy) return T[k].sum;
	pushdown(k);
	int mid=l+r>>1;
	int res=-2e9;
	if (qx<=mid) res=max(res,querynow(k<<1,l,mid,qx,qy));
	if (mid<qy) res=max(res,querynow(k<<1|1,mid+1,r,qx,qy));
	return res;
}


//不可以为空 
int main(){
	scanf("%d",&n);
	for (register int i=1; i<=(n<<2); ++i) T[i].max=T[i].tagmax=-2e9;
	for (register int i=1; i<=n; ++i) scanf("%d",&a[i]);
	for (register int i=1; i<=n; ++i) change(1,1,n,i,i,a[i]); 
	scanf("%d",&m);
	while (m--)
	{
		scanf("%s",str+1);
		if (str[1]=='Q')
		{
			//求[x,y]最大值 
			scanf("%d%d",&x,&y);
			printf("%d\n",querynow(1,1,n,x,y));
		}
		if (str[1]=='A')
		{
			//求[x,y]历史版本中最大值 
			scanf("%d%d",&x,&y);
			printf("%d\n",query(1,1,n,x,y)); 
		}
		if (str[1]=='P') 
		{
			//将[x,y]增加v 
			scanf("%d%d%d",&x,&y,&v);	
			change(1,1,n,x,y,v);
		}
	}
return 0;
}

你可能感兴趣的:(线段树)