题目分析
看到这道题,你一定想到要新开一款和历史有关的标记……
但是这个标记很不好合并……
所以就有一种独特的打标记法……
就是一个标记tag,它是一个数对
(a,b)
(
a
,
b
)
,表示这个区间内所有值都要变成
max(v+a,b)
m
a
x
(
v
+
a
,
b
)
,这样如果是区间加,就打上
(a,−inf)
(
a
,
−
i
n
f
)
标记,是区间减就打上
(−inf,b)
(
−
i
n
f
,
b
)
标记……
这个标记的合并呢……比如说当前区间原有标记
(a1,b1)
(
a
1
,
b
1
)
,还要打上新标记
(a2,b2)
(
a
2
,
b
2
)
,那么区间每一个值就变成
max(max(v+a1,b1)+a2,b2)
m
a
x
(
m
a
x
(
v
+
a
1
,
b
1
)
+
a
2
,
b
2
)
,也就是把标记变成
(a1+a2,max(b1+a2,b2))
(
a
1
+
a
2
,
m
a
x
(
b
1
+
a
2
,
b
2
)
)
…..
然后新开一款历史版标记,记为ht,表示当前这个区间最值,还未被标记tag改变,可以用的把其更新到最大的历史标记……
现在我们重载运算符,加法就是标记合并,取max就是a和b两位都取max合成的一个新标记,则pushdown操作如下:
void work(int i,node t1,node t2) {
ht[i]=max(ht[i],tag[i]+t2);//加在当前这些v上的历史标记们,增加了tag[i]+t2这个标记
hv[i]=max(hv[i],t2.cal(v[i]));//用最优历史标记更新v[i]的结果加在hv[i]上
tag[i]=tag[i]+t1,v[i]=t1.cal(v[i]);
}
void pd(int i) {
work(i<<1,tag[i],ht[i]);
work((i<<1)|1,tag[i],ht[i]);
tag[i].clear(),ht[i].clear();
}
代码
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0,w=1;char ch=' ';
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q*w;
}
const int N=100005,inf=0x3f3f3f3f;
struct node{
int a,b;
void clear() {a=0,b=-inf;}
int cal(int x) {return max(x+a,b);}
}tag[N<<2],ht[N<<2];
node operator + (node x,node y)
{return (node){max(-inf,x.a+y.a),max(x.b+y.a,y.b)};}
node max(node x,node y) {return (node){max(x.a,y.a),max(x.b,y.b)};}
int v[N<<2],hv[N<<2],n,m,a[N];
void work(int i,node t1,node t2) {
ht[i]=max(ht[i],tag[i]+t2);
hv[i]=max(hv[i],t2.cal(v[i]));
tag[i]=tag[i]+t1,v[i]=t1.cal(v[i]);
}
void up(int i) {
v[i]=max(v[i<<1],v[(i<<1)|1]);
hv[i]=max(hv[i<<1],hv[(i<<1)|1]);
}
void pd(int i) {
work(i<<1,tag[i],ht[i]);
work((i<<1)|1,tag[i],ht[i]);
tag[i].clear(),ht[i].clear();
}
void build(int s,int t,int i) {
tag[i].clear(),ht[i].clear();
if(s==t) {v[i]=hv[i]=a[s];return;}
int mid=(s+t)>>1;
build(s,mid,i<<1),build(mid+1,t,(i<<1)|1);
up(i);
}
int query(int o,int l,int r,int s,int t,int i) {
if(l<=s&&t<=r) return o?hv[i]:v[i];
int mid=(s+t)>>1,re=-inf; pd(i);
if(l<=mid) re=query(o,l,r,s,mid,i<<1);
if(mid+1<=r) re=max(re,query(o,l,r,mid+1,t,(i<<1)|1));
return re;
}
void chan(int l,int r,int s,int t,int i,node k) {
if(l<=s&&t<=r) {work(i,k,k);return;}
int mid=(s+t)>>1; pd(i);
if(l<=mid) chan(l,r,s,mid,i<<1,k);
if(mid+1<=r) chan(l,r,mid+1,t,(i<<1)|1,k);
up(i);
}
int main()
{
char ch[10];int x,y,z;
n=read();
for(RI i=1;i<=n;++i) a[i]=read();
build(1,n,1);
m=read();
while(m--) {
scanf("%s",ch),x=read(),y=read();
if(ch[0]=='Q') printf("%d\n",query(0,x,y,1,n,1));
else if(ch[0]=='A') printf("%d\n",query(1,x,y,1,n,1));
else if(ch[0]=='P') chan(x,y,1,n,1,(node){read(),-inf});
else chan(x,y,1,n,1,(node){-inf,read()});
}
return 0;
}