记$a_{i}$为时刻$i$当前cpu使用率,$b_{i}$为$a_{i}$的历史最大值
不难发现,问题即要支持:对$a_{i}$区间赋值和区间加;查询$a_{i}$和$b_{i}$的区间最大值
在线段树的节点上维护$max a,b$和一个操作序列(类似懒标记),序列中的元素为操作(赋值或加),并要求其依次执行这些操作,执行方式即令
$$
egin{cases}max a=x,max b=max(max b,max a)&(覆盖操作)\max a=max a+x,max b=max(max b,max a)&(加操作)end{cases}
$$
(注意$max b$中的$max a$均是操作后的)
但这样在下传标记时,即将父亲的操作序列接在儿子后面,显然无法保证复杂度
分析操作序列的实际影响,即令$max a$为最后一次赋值操作+其之后的加操作的和、$max b=max(max b,$每一次赋值操作+其之后加操作的最大前缀和$)$
由此,不难发现维护以下信息即可支持执行和合并(拼接):
1.加操作的极长前缀和、最大前缀和(指不包含赋值操作的前缀,为空则均记为0)
2.是否存在赋值操作
3.最后一次赋值操作后加操作的和、最大前缀和(包括该次赋值操作,若没有赋值操作则记为0和$-infty$)
4.每一次赋值操作+其之后加操作的最大前缀和的最大值(若没有赋值操作则记为$-infty$)
具体合并方式可以根据定义得到或参考代码,这里省略
时间复杂度为$o(mlog n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 struct Data{ 8 int s1,mx1,p,s2,mx2,Mx; 9 }tag[N<<2]; 10 int n,m,x,y,z,a[N],mx_a[N<<2],mx_b[N<<2]; 11 char s[11]; 12 void upd(int k,Data x){ 13 mx_b[k]=max(mx_b[k],max(mx_a[k]+x.mx1,x.Mx)); 14 if (!x.p)mx_a[k]+=x.s1; 15 else mx_a[k]=x.s2; 16 if (!tag[k].p){ 17 tag[k].mx1=max(tag[k].mx1,tag[k].s1+x.mx1); 18 tag[k].s1+=x.s1; 19 } 20 else{ 21 tag[k].mx2=max(tag[k].mx2,tag[k].s2+x.mx1); 22 tag[k].Mx=max(tag[k].Mx,tag[k].s2+x.mx1); 23 tag[k].s2+=x.s1; 24 } 25 if (x.p){ 26 tag[k].p=1,tag[k].s2=x.s2,tag[k].mx2=x.mx2; 27 tag[k].Mx=max(tag[k].Mx,x.Mx); 28 } 29 } 30 void up(int k){ 31 mx_a[k]=max(mx_a[L],mx_a[R]); 32 mx_b[k]=max(mx_b[L],mx_b[R]); 33 } 34 void down(int k){ 35 upd(L,tag[k]); 36 upd(R,tag[k]); 37 tag[k]=Data{0,0,0,0,INT_MIN,INT_MIN}; 38 } 39 void build(int k,int l,int r){ 40 tag[k]=Data{0,0,0,0,INT_MIN,INT_MIN}; 41 if (l==r){ 42 mx_a[k]=mx_b[k]=a[l]; 43 return; 44 } 45 build(L,l,mid); 46 build(R,mid+1,r); 47 up(k); 48 } 49 void update(int k,int l,int r,int x,int y,Data z){ 50 if ((l>y)||(x>r))return; 51 if ((x<=l)&&(r<=y)){ 52 upd(k,z); 53 return; 54 } 55 down(k); 56 update(L,l,mid,x,y,z); 57 update(R,mid+1,r,x,y,z); 58 up(k); 59 } 60 int query_a(int k,int l,int r,int x,int y){ 61 if ((l>y)||(x>r))return INT_MIN; 62 if ((x<=l)&&(r<=y))return mx_a[k]; 63 down(k); 64 return max(query_a(L,l,mid,x,y),query_a(R,mid+1,r,x,y)); 65 } 66 int query_b(int k,int l,int r,int x,int y){ 67 if ((l>y)||(x>r))return INT_MIN; 68 if ((x<=l)&&(r<=y))return mx_b[k]; 69 down(k); 70 return max(query_b(L,l,mid,x,y),query_b(R,mid+1,r,x,y)); 71 } 72 int main(){ 73 scanf("%d",&n); 74 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 75 build(1,1,n); 76 scanf("%d",&m); 77 for(int i=1;i<=m;i++){ 78 scanf("%s%d%d",s,&x,&y); 79 if (s[0]=='Q')printf("%d ",query_a(1,1,n,x,y)); 80 if (s[0]=='A')printf("%d ",query_b(1,1,n,x,y)); 81 if (s[0]=='P'){ 82 scanf("%d",&z); 83 update(1,1,n,x,y,Data{z,max(z,0),0,0,0,INT_MIN}); 84 } 85 if (s[0]=='C'){ 86 scanf("%d",&z); 87 update(1,1,n,x,y,Data{0,0,1,z,z,z}); 88 } 89 } 90 return 0; 91 }