• [loj3325]区间和


    关于修改,通过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 }
    View Code
  • 相关阅读:
    OpenSUSE下编译安装OpenFoam
    【一起学OpenFoam】01 OpenFoam的优势
    github+hexo搭建自己的博客网站(七)注意事项(避免read.me,CNAME文件的覆盖,手动改github page的域名)
    github+hexo搭建自己的博客网站(六)进阶配置(搜索引擎收录,优化你的url,添加RSS)
    github+hexo搭建自己的博客网站(五)进阶配置(畅言实现博客的评论)
    github+hexo搭建自己的博客网站(三)主题之外的一些基本配置(图片位置,文章目录功能)
    github+hexo搭建自己的博客网站(二)更换主题yilia
    github+hexo搭建自己的博客网站(一)基础入门
    git入门(4)团队中git保管代码常用操作
    node的包管理工具:yarn和npm
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15959492.html
Copyright © 2020-2023  润新知