关于修改,通过segment tree beats不妨转换为"将区间内的最小值均加上$x\ge 0$"
关于询问,通常即维护最大前缀/后缀/子段和,但显然无法对其直接打上述操作的懒标记
维护一个阈值$x_{\min}$,表示当且仅当$x\ge x_{\min}$时其子树内会发生某个信息的修改
关于$x_{\min}$的push-up,对(初始)所维护的信息均记录对应区间内最小值的数量即可
此时,仅在$x\ge x_{\min}$时进行递归,并分析此做法的复杂度——
定义节点的势能为其最大前缀/后缀和的长度+最大子段所选的在3种方式中最小值数量的排名
定义整颗线段树的势能为$\log n\cdot $所有节点势能和,并对节点分类讨论:
1.对于递归经过且不被完全覆盖的节点,前者单调不降,后者至多增加$o(\log^{2}n)$的势能
2.对于递归经过且被完全覆盖的节点,两者均单调不降
3.对于递归经过的叶子,其必然会减少$o(\log n)$的势能,即与第2步的递归抵消
同时,势能的范围为$[0,n\log^{2}n]$,总复杂度为$o(n\log^{2}n+m\log^{2}n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 struct Seg{ 9 int l,r,cnt; 10 ll sum; 11 bool operator < (const Seg &k)const{ 12 return (sum<k.sum)||(sum==k.sum)&&(cnt<k.cnt); 13 } 14 }; 15 struct Data{ 16 int mn,cmn,xmin; 17 Seg sum,pre,suf,ans; 18 Data(){} 19 Data(int l,ll x){ 20 mn=x,cmn=1e9,xmin=2e9; 21 sum=pre=suf=ans=sum=Seg{l,l,1,x}; 22 } 23 }f[N<<2]; 24 int n,m,p,l,r,x,a[N],tag[N<<2]; 25 void add(Seg &k,int x){ 26 k.sum+=(ll)x*k.cnt; 27 } 28 Seg add(Seg x,Seg y){ 29 return Seg{x.l,y.r,x.cnt+y.cnt,x.sum+y.sum}; 30 } 31 int get_nex(Seg x,Seg y){ 32 return min(1.0*(x.sum-y.sum)/(y.cnt-x.cnt),2e9); 33 } 34 void upd(int k,int x){ 35 tag[k]+=x,f[k].mn+=x,f[k].xmin-=x; 36 add(f[k].sum,x),add(f[k].pre,x),add(f[k].suf,x),add(f[k].ans,x); 37 } 38 void down(int k){ 39 if (tag[k]){ 40 if (f[L].mn+tag[k]==f[k].mn)upd(L,tag[k]); 41 if (f[R].mn+tag[k]==f[k].mn)upd(R,tag[k]); 42 tag[k]=0; 43 } 44 } 45 Data merge(Data x,Data y){ 46 Data ans; 47 if (x.mn>y.mn)x.sum.cnt=x.pre.cnt=x.suf.cnt=x.ans.cnt=0; 48 if (x.mn<y.mn)y.sum.cnt=y.pre.cnt=y.suf.cnt=y.ans.cnt=0; 49 ans.mn=min(x.mn,y.mn),ans.cmn=min(x.cmn,y.cmn); 50 if (x.mn!=ans.mn)ans.cmn=min(ans.cmn,x.mn); 51 if (y.mn!=ans.mn)ans.cmn=min(ans.cmn,y.mn); 52 ans.xmin=min(x.xmin,y.xmin),ans.sum=add(x.sum,y.sum); 53 Seg op=add(x.sum,y.pre),os=add(x.suf,y.sum),oa=add(x.suf,y.pre); 54 ans.pre=max(x.pre,op),ans.suf=max(y.suf,os),ans.ans=max(max(x.ans,y.ans),oa); 55 if (ans.pre.cnt<x.pre.cnt)ans.xmin=min(ans.xmin,get_nex(ans.pre,x.pre)); 56 if (ans.pre.cnt<op.cnt)ans.xmin=min(ans.xmin,get_nex(ans.pre,op)); 57 if (ans.suf.cnt<y.suf.cnt)ans.xmin=min(ans.xmin,get_nex(ans.suf,y.suf)); 58 if (ans.suf.cnt<os.cnt)ans.xmin=min(ans.xmin,get_nex(ans.suf,os)); 59 if (ans.ans.cnt<x.ans.cnt)ans.xmin=min(ans.xmin,get_nex(ans.ans,x.ans)); 60 if (ans.ans.cnt<y.ans.cnt)ans.xmin=min(ans.xmin,get_nex(ans.ans,y.ans)); 61 if (ans.ans.cnt<oa.cnt)ans.xmin=min(ans.xmin,get_nex(ans.ans,oa)); 62 return ans; 63 } 64 void build(int k,int l,int r){ 65 if (l==r){ 66 f[k]=Data(l,a[l]); 67 return; 68 } 69 build(L,l,mid),build(R,mid+1,r); 70 f[k]=merge(f[L],f[R]); 71 } 72 void update(int k,int l,int r,int x,int y,int z){ 73 if ((l>y)||(x>r)||(f[k].mn>=z))return; 74 if ((x<=l)&&(r<=y)){ 75 if ((z<f[k].cmn)&&(z-f[k].mn<f[k].xmin)){ 76 upd(k,z-f[k].mn); 77 return; 78 } 79 } 80 down(k); 81 update(L,l,mid,x,y,z); 82 update(R,mid+1,r,x,y,z); 83 f[k]=merge(f[L],f[R]); 84 } 85 Data query(int k,int l,int r,int x,int y){ 86 if ((x<=l)&&(r<=y))return f[k]; 87 down(k); 88 if (y<=mid)return query(L,l,mid,x,y); 89 if (mid<x)return query(R,mid+1,r,x,y); 90 return merge(query(L,l,mid,x,y),query(R,mid+1,r,x,y)); 91 } 92 int main(){ 93 scanf("%d%d",&n,&m); 94 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 95 build(1,1,n); 96 for(int i=1;i<=m;i++){ 97 scanf("%d%d%d",&p,&l,&r); 98 if (!p){ 99 scanf("%d",&x); 100 update(1,1,n,l,r,x); 101 } 102 if (p)printf("%lld\n",max(query(1,1,n,l,r).ans.sum,0LL)); 103 } 104 return 0; 105 }