[uoj164]V

记$a_{i}$为当前第$i$个水箱的电流,$b_{i}$为$a_{i}$的历史最大值

不难发现,问题即要支持:对$a_{i}$区间覆盖和区间加(并对0取$max$);查询某个$a_{i}$和$b_{i}$

整体思路类似于bzoj3064,仍维护$max a,b$​和操作序列,操作执行方式即令
$$
egin{cases}max a=x,max b=max(max b,max a)&(覆盖操作)\max a=max(max a+x,0),max b=max(max b,max a)&(加操作)end{cases}
$$
维护的信息也是类似地,只需要重新定义"和",并将第一个信息的两个值均用与$max a$有关的函数形式存储,那么同样也可以合并

考虑函数的形式,对两者分别讨论:

1.第一个值的函数仅取决于最小前缀和和整个序列的和,并且可以合并

2.第二个值的函数仅取决于最大前缀和、最大子段和,并且需要再维护最大后缀和(即整个序列的和-最小前缀和)来支持合并

具体合并方式可以根据定义得到或参考代码,这里省略

(不难发现也是可以支持区间查询$a_{i}$和$b_{i}$最大值的)

时间复杂度为$o(mlog n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 500005
 4 #define ll long long
 5 #define L (k<<1)
 6 #define R (L+1)
 7 #define mid (l+r>>1)
 8 struct Data{
 9     ll s1,mx1,mn1,mx,p,s2,mx2,Mx;
10 }tag[N<<2];
11 int n,m,p,x,y,z,leaf[N<<2];
12 ll a[N<<2],b[N<<2];
13 void upd(int k,Data x){
14     if (leaf[k]==1){
15         b[k]=max(b[k],max(max(a[k]+x.mx1,x.mx),x.Mx));
16         if (x.p)a[k]=x.s2;
17         else a[k]=max(a[k],-x.mn1)+x.s1;
18     }
19     if (tag[k].p){
20         tag[k].mx2=max(tag[k].mx2,max(tag[k].s2+x.mx1,x.mx));
21         tag[k].Mx=max(tag[k].Mx,max(tag[k].s2+x.mx1,x.mx));
22         tag[k].s2=max(tag[k].s2,-x.mn1)+x.s1;
23     }
24     else{
25         tag[k].mx=max(tag[k].mx,max(tag[k].s1-tag[k].mn1+x.mx1,x.mx));
26         tag[k].mn1=min(tag[k].mn1,tag[k].s1+x.mn1);
27         tag[k].mx1=max(tag[k].mx1,tag[k].s1+x.mx1);
28         tag[k].s1+=x.s1;
29     }
30     if (x.p){
31         tag[k].p=1,tag[k].s2=x.s2,tag[k].mx2=x.mx2;
32         tag[k].Mx=max(tag[k].Mx,x.Mx);
33     }
34 }
35 void down(int k){
36     upd(L,tag[k]);
37     upd(R,tag[k]);
38     tag[k]=Data{0,0,0,0,0,0,(ll)-1e18,(ll)-1e18};
39 }
40 void build(int k,int l,int r){
41     leaf[k]=0;
42     tag[k]=Data{0,0,0,0,0,0,(ll)-1e18,(ll)-1e18};
43     if (l==r){
44         leaf[k]=1;
45         scanf("%lld",&a[k]);
46         b[k]=a[k];
47         return;
48     } 
49     build(L,l,mid);
50     build(R,mid+1,r);
51 }
52 void update(int k,int l,int r,int x,int y,Data z){
53     if ((l>y)||(x>r))return;
54     if ((x<=l)&&(r<=y)){
55         upd(k,z);
56         return;
57     }
58     down(k);
59     update(L,l,mid,x,y,z);
60     update(R,mid+1,r,x,y,z);
61 }
62 ll query_a(int k,int l,int r,int x){
63     if (l==r)return a[k];
64     down(k);
65     if (x<=mid)return query_a(L,l,mid,x);
66     return query_a(R,mid+1,r,x);
67 }
68 ll query_b(int k,int l,int r,int x){
69     if (l==r)return b[k];
70     down(k);
71     if (x<=mid)return query_b(L,l,mid,x);
72     return query_b(R,mid+1,r,x);
73 }
74 int main(){
75     scanf("%d%d",&n,&m);
76     build(1,1,n);
77     for(int i=1;i<=m;i++){
78         scanf("%d%d",&p,&x);
79         if (p==1){
80             scanf("%d%d",&y,&z);
81             update(1,1,n,x,y,Data{z,z,0,z,0,0,0,(ll)-1e18});
82         }
83         if (p==2){
84             scanf("%d%d",&y,&z);
85             update(1,1,n,x,y,Data{-z,0,-z,0,0,0,0,(ll)-1e18});
86         }
87         if (p==3){
88             scanf("%d%d",&y,&z);
89             update(1,1,n,x,y,Data{0,0,0,0,1,z,z,z});
90         }
91         if (p==4)printf("%lld
",query_a(1,1,n,x));
92         if (p==5)printf("%lld
",query_b(1,1,n,x));
93     }
94     return 0;
95 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15352524.html