[bzoj3064]CPU监控

记$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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15350201.html