题目大意:给出一个长度为n的序列,有四种操作。
Q X Y:询问[x,y]的最大值
A X Y:询问[x,y]的历史最大值
P X Y Z:[x,y]中的每个数增加z
C X Y Z:[x,y]中的每个数都变成Z
对于每个区间维护六个值。
tr 区间当前的最大值
mx 区间历史的最大值
cover 区间覆盖
add 区间增加
at 区间历史最大增量
ct 区间历史最大覆盖
因为我们要维护历史最大值,所以必须保证增量的标记,和最大的覆盖标记再未被别的标记覆盖之前及时的下放给下面的区间,所以我们在每次修改之前下放标记。
注意at,ct不是一直不清的,他更准确的说维护的是一段时间内的信息。
增加标记和覆盖标记是不能同时出现的,如果打增加标记的时候已经有cover标记,那么直接将增量给cover标记;如果打cover标记的时候有增加标记,那么就将增加标记归零。
在计算at,ct的时候需要结合上层的at,ct以及当前层的add,cover.
更具体的做法还是结合代码理解一下吧。
#include
#include
#include
#include
#include
#define N 100003
#define LL long long
using namespace std;
const LL inf=1e13;
LL tr[N*4],a[N],mx[N*4],cover[N*4],add[N*4],ct[N*4],at[N*4];
int n,m;
void update(int now)
{
tr[now]=max(tr[now<<1],tr[now<<1|1]);
mx[now]=max(mx[now<<1],mx[now<<1|1]);
}
void build(int now,int l,int r)
{
cover[now]=-inf; ct[now]=-inf;
if (l==r) {
tr[now]=mx[now]=a[l];
return;
}
int mid=(l+r)/2;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
void pushdown(int now)
{
for (int i=0;i<=1;i++) {
int x=now<<1|i;
mx[x]=max(mx[x],max(ct[now],tr[x]+at[now]));
if (cover[x]==-inf) at[x]=max(at[x],add[x]+at[now]);
else ct[x]=max(ct[x],cover[x]+at[now]);
if (add[now]) {
if (cover[x]!=-inf) cover[x]+=add[now];
else add[x]+=add[now];
tr[x]+=add[now];
}
if (cover[now]!=-inf) {
tr[x]=cover[x]=cover[now];
add[x]=0;
}
ct[x]=max(ct[x],max(cover[x],ct[now]));
at[x]=max(at[x],add[x]);
}
add[now]=at[now]=0;
cover[now]=ct[now]=-inf;
}
void qjadd(int now,int l,int r,int ll,int rr,LL val)
{
if (l!=r) pushdown(now);
if (ll<=l&&r<=rr) {
tr[now]+=val; add[now]+=val; at[now]+=val;
mx[now]=max(mx[now],tr[now]);
return;
}
int mid=(l+r)/2;
if (ll<=mid) qjadd(now<<1,l,mid,ll,rr,val);
if (rr>mid) qjadd(now<<1|1,mid+1,r,ll,rr,val);
update(now);
}
void qjcover(int now,int l,int r,int ll,int rr,LL val)
{
if (l!=r) pushdown(now);
if (ll<=l&&r<=rr) {
tr[now]=ct[now]=cover[now]=val;
mx[now]=max(mx[now],tr[now]);
return;
}
int mid=(l+r)/2;
if (ll<=mid) qjcover(now<<1,l,mid,ll,rr,val);
if (rr>mid) qjcover(now<<1|1,mid+1,r,ll,rr,val);
update(now);
}
LL qjmax(int now,int l,int r,int ll,int rr,int opt)
{
if (l!=r) pushdown(now);
if (ll<=l&&r<=rr) {
if (opt==0) return mx[now];
return tr[now];
}
int mid=(l+r)/2; LL ans=-inf;
if (ll<=mid) ans=max(ans,qjmax(now<<1,l,mid,ll,rr,opt));
if (rr>mid) ans=max(ans,qjmax(now<<1|1,mid+1,r,ll,rr,opt));
return ans;
}
int main()
{
freopen("a.in","r",stdin);
//freopen("my.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&m);
for (int i=1;i<=m;i++) {
char s[3]; int x,y; LL z;
scanf("%s%d%d",s+1,&x,&y);
if (s[1]=='A') printf("%lld\n",qjmax(1,1,n,x,y,0));
if (s[1]=='Q') printf("%lld\n",qjmax(1,1,n,x,y,1));
if (s[1]=='C') scanf("%lld",&z),qjcover(1,1,n,x,y,z);
if (s[1]=='P') scanf("%lld",&z),qjadd(1,1,n,x,y,z);
}
}