末日时在做什么?有没有空?可以来拯救吗?

题目背景

今天真是多谢你了

让我体验了许多美好

我留下了如同美梦一般的回忆 不过时间到了

最后我还想拜托你一件事

希望你可以把我忘掉

在自己消失之前

心怀不想消失的愿望

希望让某个人记住我

希望能留下羁绊

我这么希望着,又有什么不可以的吗

香香甜甜的,真好闻

看起来很好吃

我遵守了...

约...约定

我非常...非常努力哦...

欢迎回来,珂朵莉

题目描述

珂朵莉给了你一个长为 nn 的序列 aa,有 mm 次操作。

  1. 把区间 [l,r][l,r] 内所有数都加上 xx。
  2. 查询区间 [l,r][l,r] 内的最大子段和,可以不选数。

输入格式

第一行两个整数 n,mn,m。

第二行 nn 个整数表示序列 aa。

后面 mm 行:

  • 1 l r x:把区间 [l,r][l,r] 内所有数加上 xx。
  • 2 l r:查询区间 [l,r][l,r] 的最大子段和。

输出格式

对于每个询问,输出一个数表示答案。

输入输出样例

输入 #1复制

5 5
-2 -3 -3 -3 -3
2 1 5
1 2 4 4
2 1 5
1 2 3 1
2 3 3

输出 #1复制

0
3
2

输入 #2复制

5 5
-2 3 3 -3 3
2 1 5
1 2 4 -4
2 1 5
1 2 3 1
2 3 3

输出 #2复制

6
3
0

题解

0 前置知识

  1. SPOJ GSS 系列
    • 最大子段和的做法,写了你就知道是啥了。
  2. 凸包、闵可夫斯基和、Jarvis
    • 不会的话可以去看一下二维凸包模板里面 ShineEternal 神仙的题解。
  3. 线段树、分块
    • 如果这个还不会那就不要做 Ynoi 了吧
  4. 基数排序
    • 这个在 v5 里面不需要,但是现在这题是 v6,所以一个高速的基数排序是很重要的~

好了,确认你都会了?

Then~start!

11 弱化

如果问题弱化为全局加区间最大子段和,这道题怎么做?

如果不带修,那么就是一个经典问题,可以维护一棵线段树,每一个节点上面维护区间和、区间最大后缀和、区间最大前缀和、区间最大子段和,合并的时候直接分类讨论即可。

然后如果加上全局加,我们还是考虑如何维护上面的四个信息。

首先区间和直接做就可以。

区间前缀和可以维护一个凸函数 f(x)f(x) 表示长度为 xx 的前缀和。

后缀和同理,记这个函数为 g(x)g(x)。

全局加 dd 然后提取最大的时候是最大化 f(x)+dxf(x)+dx(g(x)+dxg(x)+dx),显然可以凸包二分。

然后我们去考虑如何求区间最大子段和。

还是维护凸包的思路,维护一个凸函数 h(x)h(x),表示长度恰好为 xx 的子段和最大为多少。

然而这个东西是没法直接求的……

换一个思路,我们取在线段树上两个子节点的 g_L(x)gL​(x) 和 f_R(y)fR​(y),然后有关系式 h(x+y)=g_L(x)+f_R(y)h(x+y)=gL​(x)+fR​(y)。

所以这个 hh 实际上就是 g_LgL​ 和 f_RfR​ 的闵可夫斯基和再对 h_LhL​ 和 h_RhR​ 取 \maxmax。

又因为我们的 xx 是区间长度,即定义域大小是线性的,那么凸包长度就也是线性的。

所以我们对于一个大小为 ss 的节点可以 O(s)O(s) 求出这个点上面的所有凸包。

既然这样,我们就可以 O(n\log n)O(nlogn) 建出线段树。

提取答案的时候,每一个节点凸包二分,共 \log nlogn 个节点,故每次询问的复杂度为 O(\log^2 n)O(log2n)。

注意:P5073 的解法与此稍有不同,因为 P5073 可以也需要通过离线转换为只加正数从而达到均摊单次询问 O(\log n)O(logn),但是这题并不完全需要,后面会讲到。

我就是因为受 P5073 的思路制约导致在这题上面卡了好几天……

22 本题高复杂度解法

我们对这个序列分块,在每一块上面建 11 中所说的线段树,每次整体修改可以直接做,零散修改重构线段树,整体查询和零散查询都查询线段树。

这样如果块长为 ss,整体修改 O(1)O(1),零散修改 O(s\log s)O(slogs),整体查询 O(\log s)O(logs),零散查询 O(\log^2 s)O(log2s),可以得到一个复杂度为 O(n\sqrt n\log n)O(nn​logn) 的解法。

灵魂拷问:能 过 吗?

显然是不能的。

于是就有了——

33 本题低复杂度解法

我们发现复杂度有两个瓶颈:一是零散修改,二是整体查询。分开讨论怎么优化。

3.13.1 零散修改优化

真的有必要重构整棵线段树吗?

不要忘了:

  1. 线段树的子树还是线段树
  2. 这里的线段树支持整体加,不支持区间加

所以我们可以在零散修改的时候在终止节点上面打标记,非终止节点线性重构。

对于标记的下放,我们可以这样处理:我们在线段树上搞一个节点整体加的标记,这个是正常下放的;然后再在凸包上面维护一个凸包整体加的标记,这个标记是只叠加不下放的。取凸包内节点的时候考虑叠加的正比例函数对点的位置的影响即可。

因为每一层非终止节点的数量是 O(1)O(1) 的,所以等比数列求和一下零散修改就变成 O(s)O(s) 的了,但是常数比较大。

你可能会问,这里的线段树不是只支持加正数的吗?如果加负数怎么做呢?

事实是:这个线段树支持加负数。 因为 P5073 限制了我们的复杂度到 O(\log n)O(logn),而这题并没有。 所以采用二分的方式提取答案,是可以支持加负数的。

所以零散修改的复杂度就下降到了线性。

3.23.2 整体查询优化

首先我们引入一个科技:逐块处理。

这个科技适用于修改和查询都按块独立且允许离线的问题。

对于这个问题,区间加肯定是按块独立的没话说,最大子段和我们也有办法快速合并,所以就可以逐块处理。

而逐块处理就是离线每一个输入的操作对这个块的操作,然后依次算一遍第一块的所有操作,算一遍第二块的所有操作……

这样的好处在于,如果我们的第 ii 次操作和第 jj 次操作修改了这个块 (i<j)(i<j),那么此时这两个操作之间的所有操作都可以 随意改变顺序,而传统分块是做不到这一点的。


现在来看如何使用这个科技解决这题。

我们发现,整体查询一定是提取线段树根上面那个凸包,而因为整体修改是用一个全局 tag 保存,所以 根上一定是没有标记的

既然这样,我们就可以把所有查询按照查询时整体加 tag 的值升序排序,然后转换成整体加只加正数。(这里就是逐块处理的应用——改变询问顺序。)

这样在根上面提取答案的时候可以类似 P5073 那样搞个指针往右爬,从而 O(s)O(s) 处理所有询问。零散修改重构凸包的时候,直接把指针重置为 00 即可。

这样处理询问的复杂度就是 O(ms)O(ms)。

证明:

我们定义一个块的势能 EE 为根上面的指针距离块右端点的距离。

那么显然初始的势能 \sum E=O(n)∑E=O(n)。

那么我们每次零散操作会把指针置回 00,导致增加 O(s)O(s) 的势能。

而每一次操作只会导致 O(1)O(1) 个块被零散操作。

故总零散操作的数量是 O(m)O(m) 量级的。

所以总势能是 O(ms)O(ms) 的。

又因为每次爬指针的时候是 O(1)O(1) 时间减少 O(1)O(1) 势能,故总时间最大为 O(ms)O(ms)。

Q.E.D.


但是还有一个问题,排序的复杂度仍然是 O(ms\log m)O(mslogm)。

所以换成基数排序,这样就实实在在地优化到 O(ms)O(ms) 了。

那么,现在得到了一个零散修改 O(s)O(s),零散查询 O(\log^2s)O(log2s)(当然你也可以用暴力扫的方式来 O(s)O(s),不过我觉得这样比较方便),整体修改 O(1)O(1),整体查询均摊 O(1)O(1)(因为是 O(ms)O(ms) 时间, O(ms)O(ms) 次查询)的算法。

取 s=\sqrt ns=n​,得此时算法的复杂度为 O(m\sqrt n)O(mn​)。

芜湖,起飞!

44 常数优化

但是 lxl 显然不会让你就这样愉快地过掉这道题……

于是我们开始卡常:

4.14.1 优化 1

我们发现,\log_{10}vlog10​v 和 \log_2nlog2​n 的差距不是很大,除 1010 又会有很大的常数。所以基数排序的基数取 20482048,这样可以位运算,\log_{2048}vlog2048​v 也很小,速度就会快不少。

4.24.2 优化 2

我们发现,每次排序的时候用 2048 个 vector 来保存桶会导致动态分配内存占用巨大的时间。

然而我们在排整数序列的时候,是用 2048 个 int 来保存每一个数的出现次数,然后再放回到数组里面,这样就避免了分配内存的压力。

这里的应用是单关键字排序结构体,所以如果我们能把结构体的下标强行附加到全局 tag 上,一切问题就都解决了。

显然我们可以做到这一点,我们把下标乘上 2^{35}235 然后加到全局 tag 上面,排序仍然只排 33 次。这样因为排序只会考虑到 3333 位以下的部分,下标就不会参与排序。

于是我们就得到了按照关键字排好序的下标数组,对应回去即可。全过程中可以完全避免动态分配内存,就会有很大的速度提升。

而且在结合了优化 22 之后,可以将基数排序的基数改为 256256,由于缓存的影响,速度会有极大的提升。

4.34.3 优化 3

维护凸包时不要使用 vector,使用数组和指针静态分配内存。这样进一步减少了 vector 动态内存分配的压力。

4.44.4 优化 4

由于在块长不变的时候内存分配情况一定不会变,所以只需要在第一个块分配一下内存,最后一个块重新分配一下内存就可以了,不需要每次都重新分配。

4.54.5 优化 5

一杯茶,一包烟,一个块长调一天。


加上这些常数优化,我就轻松(?)过掉了这题。

上面的常数优化大部分都围绕着消除动态分配内存导致的巨大常数,这个思路在其他场景下也适用。

#define got(x,len) (((x)-1)/(len)+1)
#define LB(x,len) (((x)-1)*(len)+1)
#define RB(x,len) min(((x)*(len)),n)
struct Question{
    int op=0,lft=0,rgt=0;
    long long v=0;
}que[maxn];
namespace KamisatoAyaka{
    int blk[maxn/maxs+5],brgt[maxn/maxs+5],pos[maxn],tot;
    struct Point{
        long long x,y;
        inline Point operator+(register const Point &b)const{
            return{x+b.x,y+b.y};
        }
        inline Point operator-(register const Point &b)const{
            return{x-b.x,y-b.y};
            }
        inline bool operator <=(register const Point &b)const{
            return x*b.y>=y*b.x;
        }
    } pool[maxn];
    struct Hull{
        Point *pnt;
        int siz,mxpnt;
        long long tag;
        inline Point operator [](register const int x){
            return{pnt[x].x,pnt[x].y+tag*pnt[x].x};
        }
        inline void insert(register Point x){
            pnt[x.x].y=max(pnt[x.x].y,x.y);
        }
        inline void pushBack(register Point x){
            pnt[siz++]=x;
        }
        inline void init(register int len){
            pnt[0]={0,0},siz=len+1,tag=0;
            for(register int i=1;i<=len;++i) 
                pnt[i]={i,-inf};
        }
        inline void Jarvis(){
            if(siz<=2) return;
            int top=1;
            for(register int i=2;i<siz;++i){
                if(pnt[i].y==-inf) continue;
                while(top>=1&&(pnt[top]-pnt[top-1]) <=(pnt[i]-pnt[top-1]))
                    --top;
                pnt[++top]=pnt[i];
            }
            siz=top+1,tag=0;
        }
        inline bool check(register int x,register long long addv){
            return(pnt[x+1].x-pnt[x].x)*(tag+addv)+pnt[x+1].y-pnt[x].y>0;
        }
        inline long long Maxv(register long long addv){
            while(mxpnt<siz-1&&check(mxpnt,addv))
                ++mxpnt;
            return pnt[mxpnt].x*(tag+addv)+pnt[mxpnt].y;
        }
        inline long long MaxvBS(register long long addv){
            register int lft=-1,rgt=siz-1,mid;
            for(mid=lft+rgt>>1;lft<rgt-1;mid=lft+rgt>>1)
                if(check(mid,addv))
                    lft=mid;
                else 
                    rgt=mid;
            mxpnt=rgt;
            return pnt[mxpnt].x*(tag+addv)+pnt[mxpnt].y;
        }
    };
    struct AyakaNode{
        long long lmax,rmax,midmax,sum;
        inline AyakaNode operator+(const AyakaNode &b)const{
            return{max(lmax,sum+b.lmax),max(rmax+b.sum,b.rmax),max(max(midmax,b.midmax),rmax+b.lmax),sum+b.sum};
        }
    } res[maxn];
    struct LineTree{
        Hull lmax[maxs<<2],rmax[maxs<<2],midmax[maxs<<2];
        long long sum[maxs<<2],tag[maxs<<2];
        inline void init(register int rt,register int lft,register int rgt){
            lmax[rt].pnt=pool+tot;
            tot+=rgt-lft+3;
            rmax[rt].pnt=pool+tot;
            tot+=rgt-lft+3;
            midmax[rt].pnt=pool+tot;
            tot+=rgt-lft+3;
            if(lft==rgt) return;
            int mid=(lft+rgt)>>1;
            init(rt<<1,lft,mid);
            init(rt<<1|1,mid+1,rgt);
        }
        inline void preSufMerge(register Hull &c,register Hull &a,register Hull &b,register Point addb){
            for(register int i=0,t=a.siz;i<t;++i)
                c.pushBack(a[i]);
            for(register int i=0,t=b.siz;i<t;++i)
                c.pushBack(addb+b[i]);
            c.Jarvis();
        }
        inline void Minkowski(register Hull &c,register Hull &a,register Hull &b){
            int i=0,j=0,sa=a.siz-1,sb=b.siz-1;
            for(c.insert(a[i]+b[j]);i<sa&&j<sb;c.insert(a[i]+b[j]))
                a[i+1]-a[i]<=b[j+1]-b[j]?++j:++i;
            while(i<sa)
                c.insert(a[++i]+b[j]);
            while(j<sb)
                c.insert(a[i]+b[++j]);
        }
        inline void pushUp(register int rt,register int lft,register int rgt){
            int mid=(lft+rgt)>>1;
            preSufMerge(lmax[rt],lmax[rt<<1],lmax[rt<<1|1],{mid-lft+1,sum[rt<<1]});
            preSufMerge(rmax[rt],rmax[rt<<1|1],rmax[rt<<1],{rgt-mid,sum[rt<<1|1]});
            midmax[rt].init(rgt-lft+1);
            for(register int i=0,t=midmax[rt<<1].siz;i<t;++i)
                midmax[rt].insert(midmax[rt<<1][i]);
            for(register int i=0,t=midmax[rt<<1|1].siz;i<t;++i)
                midmax[rt].insert(midmax[rt<<1|1][i]);
            Minkowski(midmax[rt],rmax[rt<<1],lmax[rt<<1|1]);
            midmax[rt].Jarvis();
            lmax[rt].mxpnt=rmax[rt].mxpnt=midmax[rt].mxpnt=0;
            sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        }
        inline void add(register int rt,register int lft,register int rgt,register long long d){
            tag[rt]+=d;
            lmax[rt].tag+=d;
            rmax[rt].tag+=d;
            midmax[rt].tag+=d;
            sum[rt]+=d*(rgt-lft+1);
        }
        inline void pushDown(register int rt,register int lft,register int rgt){
            if(lft==rgt||!tag[rt]) return;
            int mid=(lft+rgt)>>1;
            add(rt<<1,lft,mid,tag[rt]);
            add(rt<<1|1,mid+1,rgt,tag[rt]);
            tag[rt]=0;
        }
        inline void buildTree(register int rt,register int lft,register int rgt,register int bid){
            if(lft==rgt){
                sum[rt]=a[lft+blk[bid]-1];
                lmax[rt].pushBack({0,0});
                lmax[rt].pushBack({1,sum[rt]});
                rmax[rt].pushBack({0,0});
                rmax[rt].pushBack({1,sum[rt]});
                midmax[rt].pushBack({0,0});
                midmax[rt].pushBack({1,sum[rt]});
                return;
            }
            int mid=(lft+rgt)>>1;
            buildTree(rt<<1,lft,mid,bid);
            buildTree(rt<<1|1,mid+1,rgt,bid);
            pushUp(rt,lft,rgt);
        }
        inline void clear(register int rt,register int lft,register int rgt){
            lmax[rt].siz=rmax[rt].siz=midmax[rt].siz=0;
            lmax[rt].mxpnt=rmax[rt].mxpnt=midmax[rt].mxpnt=0;
            lmax[rt].tag=rmax[rt].tag=midmax[rt].tag=0;
            tag[rt]=0;
            if(lft==rgt) return;
            int mid=(lft+rgt)>>1;
            clear(rt<<1,lft,mid);
            clear(rt<<1|1,mid+1,rgt);
        }
        inline void change(register int rt,register int lft,register int rgt,register int l,register int r,register long long d){
            if(lft==l&&rgt==r)
                return add(rt,lft,rgt,d);
            pushDown(rt,lft,rgt);
            int mid=(lft+rgt)>>1;
            if(r<=mid) 
                change(rt<<1,lft,mid,l,r,d);
            else if(l>mid) 
                change(rt<<1|1,mid+1,rgt,l,r,d);
            else 
                change(rt<<1,lft,mid,l,mid,d),change(rt<<1|1,mid+1,rgt,mid+1,r,d);
            lmax[rt].siz=rmax[rt].siz=midmax[rt].siz=0;
            pushUp(rt,lft,rgt);
        }
        inline AyakaNode query(register int lft,register int rgt,register long long addv){
            return{lmax[1].Maxv(addv),rmax[1].Maxv(addv),midmax[1].Maxv(addv),sum[1]+(rgt-lft+1)*addv};
        }
        inline AyakaNode ask(register int rt,register int lft,register int rgt,register int l,register int r,register long long addv){
            if(lft==l&&rgt==r)
                return rt==1?query(l,r,addv):(AyakaNode){lmax[rt].MaxvBS(addv),rmax[rt].MaxvBS(addv),midmax[rt].MaxvBS(addv),sum[rt]+(r-l+1)*addv};
            pushDown(rt,lft,rgt);
            register int mid=(lft+rgt)>>1;
            if(r<=mid)
                return ask(rt<<1,lft,mid,l,r,addv);
            else if(l>mid)
                return ask(rt<<1|1,mid+1,rgt,l,r,addv);
            else
                return ask(rt<<1,lft,mid,l,mid,addv)+ask(rt<<1|1,mid+1,rgt,mid+1,r,addv);
        }
    };
    struct QuestionForBlock{
        int lft=0,rgt=0,id=0;
        long long v=0,typ=0;
        inline bool operator<(register const QuestionForBlock &b)const{
            return v<b.v;
        }
    };
    struct Block{
        LineTree ayaka;
        int bid,bn,bm,cnt[maxr];
        QuestionForBlock neq[maxn],tmp[maxn];
        long long tag,valt[maxn],val[maxn];
        inline void update(register long long d){
            tag+=d;
        }
        inline void change(register int lft,register int rgt,register long long d){
            if(d==0) return;
            if(lft==1&&rgt==bn)
                return tag+=d,void();
            neq[bm++]={lft,rgt,0,tag,d};
        }
        inline void query(register int lft,register int rgt,register int id){
            neq[bm++]={lft,rgt,id,tag,0};
        }
        #define geted(x,d)(((x)>>((d)*bit))&(maxr-1))
        inline void radixSort(register int lft,register int rgt){
            if(rgt-lft<=1500) 
                return sort(neq+lft,neq+rgt),void();
            register long long *x=val,*y=valt;
            register int tt=rgt-lft;
            for(register int i=lft;i<rgt;++i) 
                x[i-lft]=y[i-lft]=neq[i].v|((1ll*i)<<35);
            for(register int d=0;d<4;++d){
                for(register int i=0;i<maxr;++i) 
                    cnt[i]=0;
                for(register int i=0;i<tt;++i) 
                    ++cnt[geted(x[i],d)];
                for(register int i=1;i<maxr;++i) 
                    cnt[i]+=cnt[i-1];
                for(register int i=tt-1;i>=0;--i)
                     y[--cnt[geted(x[i],d)]]=x[i];
                swap(x,y);
            }
            for(register int i=lft;i<rgt;++i) 
                tmp[i-lft]=neq[i];
            for(register int i=lft;i<rgt;++i) 
                neq[i]=tmp[(x[i-lft]>>35)-lft];
        }
        inline void init(){
            register long long mintag=0;
            for(register int i=0;i<bm;++i) 
                mintag=min(mintag,neq[i].v);
            for(register int i=0;i<bm;++i) 
                neq[i].v-=mintag;
            for(register int i=blk[bid],t=brgt[bid];i<=t;++i) 
                a[i]+=mintag;
            ayaka.buildTree(1,1,bn,bid);
            register int last=0;
            for(register int i=0;i<bm;++i)
                if(neq[i].typ){
                    if(i!=last)
                        radixSort(last,i);
                    last=i+1;
            }
            if(last!=bm) 
                radixSort(last,bm);
        }
        inline void solve(){
            for(register int i=0;i<bm;++i)
                if(!neq[i].typ){
                    if(i&&neq[i-1].typ){
                        ayaka.lmax[1].MaxvBS(neq[i].v);
                        ayaka.rmax[1].MaxvBS(neq[i].v);
                        ayaka.midmax[1].MaxvBS(neq[i].v);
                    }
                    res[neq[i].id]=res[neq[i].id]+ayaka.ask(1,1,bn,neq[i].lft,neq[i].rgt,neq[i].v);
                }
                else 
                    ayaka.change(1,1,bn,neq[i].lft,neq[i].rgt,neq[i].typ);
        }
        inline void clear(){
            bm=tag=0;
            ayaka.clear(1,1,bn);
        }
    } ayk;
    inline void work(){  
        register int qcnt;
        for(register int i=1;i<=n;++i) 
            pos[i]=got(i,maxs);
        for(register int i=1;i<=pos[n];++i){
            blk[i]=LB(i,maxs);
            brgt[i]=RB(i,maxs);
        }
        for(register int i=1;i<=pos[n];++i){
            qcnt=0;
            for(register int j=1;j<=m;++j){
                if(que[j].op==2)
                    ++qcnt;
                if(que[j].lft>brgt[i]||que[j].rgt<blk[i])
                    continue;
                if(que[j].op==1){
                    if(que[j].lft<=blk[i]&&que[j].rgt>=brgt[i]) 
                        ayk.update(que[j].v);
                    else 
                        ayk.change(max(que[j].lft,blk[i])-blk[i]+1,min(que[j].rgt,brgt[i])-blk[i]+1,que[j].v);
                }
                else 
                    ayk.query(max(que[j].lft,blk[i])-blk[i]+1,min(que[j].rgt,brgt[i])-blk[i]+1,qcnt);
            }
            ayk.bid=i;
            ayk.bn=brgt[i]-blk[i]+1;
            if(i==1||i==pos[n])
                tot=0,ayk.ayaka.init(1,1,ayk.bn);
            ayk.init();
            ayk.solve();
            ayk.clear();
        }
        for(register int i=1;i<=qcnt;++i)
            quickWrite(res[i].midmax,'\n');
    }
}
namespace AetherKamisatoAyaka{
    long long check[100001],nowu,cnt1,cnt2,c[100001],qf[100001];
    bool check1,hmz;
    inline void add(register long long now,register long long v){
        for(;now<=n;now+=now & -now) 
            c[now]+=v;
    }
    inline long long sum(register long long tmp){
        register long long s=0;
        for(;tmp>0;tmp -= tmp & -tmp) s+=c[tmp];
        return s;
    }
    inline void getMid(register long long pos,register long long lft,register long long rgt,register bool vis);
    inline void getMid1(register long long pos,register long long lft,register long long rgt,register bool vis);
    inline void getMid2(register long long pos,register long long lft,register long long rgt,register bool vis);
    inline void getMin(register long long pos,register long long lft,register long long rgt);
    namespace Ayakawork1{
        struct Node{
            long long lft,rgt,mid,sum,maxx,minn,tag;
            bool need;
            Node(register long long lft=0,register long long rgt=0,register long long mid=0,register long long sum=0,register long long maxx=0,register long long minn=0,register long long tag=0):lft(lft),rgt(rgt),mid(mid),sum(sum),maxx(maxx),minn(minn),tag(tag){need=0;}
        } tree[262144];
        inline Node merge(register Node x,register Node y){
            return Node(max(x.lft,x.sum+y.lft),max(y.rgt,y.sum+x.rgt),max(max(x.mid,y.mid),x.rgt+y.lft),x.sum+y.sum,max(x.maxx,y.maxx),min(x.minn,y.minn),0ll);
        }
        inline void pushDown(register long long now,register long long lft,register long long rgt){
            register long long mid=(lft+rgt)>>1;
            if(tree[now].tag!=0){
                long long mid=(lft+rgt)>>1;
                tree[now<<1].sum +=(mid-lft+1)*tree[now].tag;
                tree[now<<1|1].sum +=(rgt-mid)*tree[now].tag;
                tree[now<<1].tag+=tree[now].tag;
                tree[now<<1|1].tag+=tree[now].tag;
                tree[now<<1].maxx+=tree[now].tag;
                tree[now<<1|1].maxx+=tree[now].tag;
                tree[now<<1].minn+=tree[now].tag;
                tree[now<<1|1].minn+=tree[now].tag;
                tree[now<<1].lft=tree[now<<1].rgt=tree[now<<1].mid=max(tree[now<<1].sum,0ll);
                tree[now<<1|1].lft=tree[now<<1|1].rgt=tree[now<<1|1].mid=max(tree[now<<1|1].sum,0ll);
                tree[now].tag=0;
            }
            if(tree[now].need&&lft!=rgt){
                tree[now<<1].need=true;
                tree[now<<1|1].need=true;
                getMid(now<<1,lft,mid,true);
                getMid(now<<1|1,mid+1,rgt,true);
                tree[now].need=false;
            }
        }
        inline void buildTree(register long long now,register long long lft,register long long rgt){
            if(lft==rgt){
                tree[now].need=false;
                tree[now].lft=tree[now].rgt=tree[now].mid=max(a[lft],0ll);
                tree[now].sum=tree[now].minn=tree[now].maxx=a[lft];
                tree[now].tag=0;
                return;
            }
            tree[now].need=false;
            register long long mid=(lft+rgt)>>1;
            buildTree(now<<1,lft,mid),buildTree(now<<1|1,mid+1,rgt);
            tree[now]=merge(tree[now<<1],tree[now<<1|1]);
        }
        inline void update(register long long now,register long long lft,register long long rgt,register long long x,register long long y,register long long w){
            if(lft>y||rgt<x) return;
            if(x<=lft&&rgt<=y){
                if(tree[now].maxx+w<=0||tree[now].minn+w>=0){
                    tree[now].sum +=(rgt-lft+1)*w;
                    tree[now].tag+=w;
                    tree[now].maxx+=w;
                    tree[now].minn+=w;
                    tree[now].lft=tree[now].rgt=tree[now].mid=max(tree[now].sum,0ll);
                    tree[now].need=false;
                    return;
                }
                else if((!check1&&rgt-lft+1<=500) ||(check1&&rgt-lft+1<=5000)){
                    tree[now].sum +=(rgt-lft+1)*w;
                    tree[now].tag+=w;
                    tree[now].maxx+=w;
                    tree[now].minn+=w;
                    tree[now].need=true;
                    getMid(now,lft,rgt,true);
                    return;
                }
            }
            if(rgt-lft+1<=500){
                getMin(now,lft,rgt);
                if(tree[now].maxx<=0||tree[now].minn>=0) 
                    tree[now].mid=tree[now].lft=tree[now].rgt=max(0ll,tree[now].sum);
                else 
                    getMid(now,lft,rgt,true);
                return;
            }
            pushDown(now,lft,rgt);
            register long long mid=(lft+rgt)>>1;
            update(now<<1,lft,mid,x,y,w);
            update(now<<1|1,mid+1,rgt,x,y,w);
            tree[now]=merge(tree[now<<1],tree[now<<1|1]);
        }
        inline Node query(register long long now,register long long lft,register long long rgt,register long long x,register long long y){
            if(x<=lft&&rgt<=y)
                return tree[now];
            if(lft<=x&&rgt<=y&&(rgt-x+1)<=700&&(tree[now].need||rgt-x<=500))
                return getMid(0,x,rgt,true),tree[0];
            if(lft>=x&&rgt>=y&&(y-lft+1)<=700&&(tree[now].need||y-lft<=500))
                return getMid(0,lft,y,true),tree[0];
            register long long mid=(lft+rgt)>>1;
            pushDown(now,lft,rgt);
            Node res;
            if(x>mid) 
                res=query(now<<1|1,mid+1,rgt,x,y);
            else if(y<=mid)
                res=query(now<<1,lft,mid,x,y);
            else {
                Node resa=query(now<<1,lft,mid,x,y),resb=query(now<<1|1,mid+1,rgt,x,y);
                res=Node(max(resa.lft,resa.sum+resb.lft),max(resb.rgt,resb.sum+resa.rgt),max(resa.mid,max(resb.mid,resa.rgt+resb.lft)),resa.sum+resb.sum,0ll,0ll,0ll);
            }
            tree[now]=merge(tree[now<<1],tree[now<<1|1]);
            return res;
        }
    }
    namespace Ayakawork2{
        long long eps;
        struct Node{
            long long lft,rgt,mid,sum,maxx,minn,tag;
            bool check;
        } tree[262144];
        inline bool get(register Node now,register long long len){
            return(now.maxx<=0||now.minn>=0);
        }
        inline void pushDown(register long long now,register long long lft,register long long rgt){
            long long mid=(lft+rgt)>>1;
            tree[now<<1].sum+=(mid-lft+1)*tree[now].tag,
            tree[now<<1|1].sum+=(rgt-mid)*tree[now].tag;
            tree[now<<1].tag+=tree[now].tag,
            tree[now<<1|1].tag+=tree[now].tag;
            tree[now<<1].maxx+=tree[now].tag,
            tree[now<<1|1].maxx+=tree[now].tag;
            tree[now<<1].minn+=tree[now].tag,
            tree[now<<1|1].minn+=tree[now].tag;
            tree[now<<1].check=get(tree[now<<1],mid-lft+1);
            tree[now<<1|1].check=get(tree[now<<1|1],rgt-mid);
            tree[now].tag=0;
        }
        inline Node merge(register Node x,register Node y,register long long len){
            Node res={max(x.lft,x.sum+y.lft),max(y.rgt,y.sum+x.rgt),max(max(x.mid,y.mid),x.rgt+y.lft),x.sum+y.sum,max(x.maxx,y.maxx),min(x.minn,y.minn)};
            if(x.check||y.check)
                res.check=true;
            else 
                res.check=false;
            return res;
        }
        inline void buildTree(register long long now,register long long lft,register long long rgt){
            tree[now].tag=0;
            tree[now].check=false;
            if(lft==rgt){
                tree[now].maxx=tree[now].minn=tree[now].sum=a[lft];
                return;
            }
            register long long mid=(lft+rgt)>>1;
            buildTree(now<<1,lft,mid);
            buildTree(now<<1|1,mid+1,rgt);
            tree[now]=merge(tree[now<<1],tree[now<<1|1],rgt-lft+1);
        }
        inline void update(register long long now,register long long lft,register long long rgt,register long long x,register long long y,register long long w){
            if(lft>y||rgt<x) return;
            if(x<=lft&&rgt<=y){
                tree[now].sum +=(rgt-lft+1)*w;
                tree[now].maxx+=w;
                tree[now].minn+=w;
                tree[now].tag+=w;
                if((tree[now].maxx<=0||tree[now].minn>=0)&&rgt-lft+1>=eps)
                    tree[now].check=true;
                else
                    tree[now].check=false;
                return;
            }
            pushDown(now,lft,rgt);
            register long long mid=(lft+rgt)>>1;
            update(now<<1,lft,mid,x,y,w);
            update(now<<1|1,mid+1,rgt,x,y,w);
            tree[now]=merge(tree[now<<1],tree[now<<1|1],rgt-lft+1);
        }
        inline Node query(register long long now,register long long lft,register long long rgt,register long long x,register long long y){
            tree[now].check=get(tree[now],rgt-lft+1);
            if(lft>y||rgt<x)
                return Node{-10000000,-10000000,-10000000,0,0,0,0,0};
            if(x<=lft&&rgt<=y){
                if(tree[now].maxx<=0||tree[now].minn>=0){
                    tree[now].lft=tree[now].rgt=tree[now].mid=max(tree[now].sum,0ll);
                    return tree[now];
                }
                else if(rgt-lft+1<=300){
                    getMid(now,lft,rgt,false);
                    return tree[now];
                }
            }
            Node res;
            pushDown(now,lft,rgt);
            register long long mid=(lft+rgt)>>1;
            if(lft>mid) 
                res=query(now<<1,lft,mid,x,y);
            else if(rgt<=mid) 
                res=query(now<<1|1,mid+1,rgt,x,y);
            else{
                Node a=query(now<<1,lft,mid,x,y),b=query(now<<1|1,mid+1,rgt,x,y);
                res={max(a.lft,a.sum+b.lft),max(b.rgt,b.sum+a.rgt),max(max(a.mid,b.mid),a.rgt+b.lft),a.sum+b.sum,max(a.maxx,b.maxx),min(a.minn,b.minn)};
            }
            tree[now]=merge(tree[now<<1],tree[now<<1|1],rgt-lft+1);
            return res;
        }
    }
    inline void work(){
        register long long lft,rgt,w;
        for(register long long i=1;i<=n;++i)
            qf[i]=a[i]-a[i-1],add(i,qf[i]);
        Ayakawork1::buildTree(1,1,n);
        for(register long long k=1;k<=m;++k){
            lft=que[k].lft;
            rgt=que[k].rgt;
            w=que[k].v;
            if(!lft) 
                ++lft;
            nowu=lft;
            if(!hmz){
                if(que[k].op==1){
                    qf[lft]+=w;
                    qf[rgt+1]-=w;
                    add(lft,w);
                    add(rgt+1,-w);
                    Ayakawork1::update(1,1,n,que[k].lft,que[k].rgt,que[k].v);
                }
                else{
                    if(rgt-lft+1<=50000){
                        register long long res=0,now=0,qlft=sum(lft),i;
                        for(i=lft;i<=rgt-11;i+=12){
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+1];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+2];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+3];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+4];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+5];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+6];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+7];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+8];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+9];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+10];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+11];
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[i+12];
                        }
                        while(i<=rgt){
                            now=(now<0?0:now)+qlft;
                            res=(res>now?res:now);
                            qlft+=qf[++i];
                        }
                        quickWrite(res,'\n');
                    }
                    else
                        quickWrite(Ayakawork1::query(1,1,n,que[k].lft,que[k].rgt).mid,'\n');
                }
            }
        }
    }
    inline void getMid(register long long pos,register long long lft,register long long rgt,register bool vis){
        if(!pos||!vis||!check1 ||(lft!=nowu&&Ayakawork1::tree[pos].maxx>=1e8+1e5)) 
            getMid1(pos,lft,rgt,vis);
        else 
            getMid2(pos,lft,rgt,vis);
    }
    inline void getMid1(register long long pos,register long long lft,register long long rgt,register bool vis){
        register long long res[3]={0,0,0},now[3]={0,0,0},qlft=sum(lft),i;
        for(i=lft;i<=rgt-3;i+=4){
            now[1]+=qlft;
            res[1]=(res[1]>now[1]?res[1]:now[1]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+1];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[1]+=qlft;
            res[1]=(res[1]>now[1]?res[1]:now[1]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+2];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[1]+=qlft;
            res[1]=(res[1]>now[1]?res[1]:now[1]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+3];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[1]+=qlft;
            res[1]=(res[1]>now[1]?res[1]:now[1]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+4];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
        }
        while(i<=rgt){
            now[1]+=qlft;
            res[1]=(res[1]>now[1]?res[1]:now[1]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+1];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            ++i;
        }
        if(vis){
            Ayakawork1::tree[pos].lft=res[1];
            Ayakawork1::tree[pos].rgt=now[2];
            Ayakawork1::tree[pos].mid=res[2];
        }
        else{
            Ayakawork2::tree[pos].lft=res[1];
            Ayakawork2::tree[pos].rgt=now[2];
            Ayakawork2::tree[pos].mid=res[2];
        }
    }
    inline void getMid2(register long long pos,register long long lft,register long long rgt,register bool vis){
        register long long now[3]={0,0,0},qlft=sum(lft),i,res[3]={0,0,0};
        for(i=lft;i<=rgt-12;i+=13){
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+1];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+2];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+3];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+4];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+5];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+6];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+7];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+8];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+9];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+10];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+11];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+12];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+13];
            res[2]=(res[2]>now[2]?res[2]:now[2]);
        }
        while(i<=rgt){
            now[2]=(now[2]<0?0:now[2])+qlft;
            qlft+=qf[i+1];
            res[2]=(res[2]>now[2]?res[2]:now[2]),
            ++i;
        }
        if(vis){
            Ayakawork1::tree[pos].lft=res[1];
            Ayakawork1::tree[pos].rgt=now[2];
            Ayakawork1::tree[pos].mid=res[2];
        }
        else{
            Ayakawork2::tree[pos].lft=res[1];
            Ayakawork2::tree[pos].rgt=now[2];
            Ayakawork2::tree[pos].mid=res[2];
        }
    }
    inline void getMin(register long long pos,register long long lft,register long long rgt){
        register long long i,sm=0,maxx=-1e10,minn=1e10,qlft=sum(lft);
        for(i=lft;i<=rgt-11;i+=12){
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+1];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+2];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+3];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+4];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+5];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+6];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+7];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+8];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+9];
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+10];
            sm+=qlft;maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+11];
            sm+=qlft;maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[i+12];
        }
        while(i<=rgt){
            sm+=qlft;
            maxx=(maxx<qlft?qlft:maxx);
            minn=(minn<qlft?minn:qlft);
            qlft+=qf[++i];
        }
        Ayakawork1::tree[pos].sum=sm;
        Ayakawork1::tree[pos].maxx=maxx;
        Ayakawork1::tree[pos].minn=minn;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值