题目背景
今天真是多谢你了
让我体验了许多美好
我留下了如同美梦一般的回忆 不过时间到了
最后我还想拜托你一件事
希望你可以把我忘掉
在自己消失之前
心怀不想消失的愿望
希望让某个人记住我
希望能留下羁绊
我这么希望着,又有什么不可以的吗
香香甜甜的,真好闻
看起来很好吃
我遵守了...
约...约定
我非常...非常努力哦...
欢迎回来,珂朵莉
题目描述
珂朵莉给了你一个长为 nn 的序列 aa,有 mm 次操作。
- 把区间 [l,r][l,r] 内所有数都加上 xx。
- 查询区间 [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 前置知识
- SPOJ GSS 系列
- 最大子段和的做法,写了你就知道是啥了。
- 凸包、闵可夫斯基和、Jarvis
- 不会的话可以去看一下二维凸包模板里面 ShineEternal 神仙的题解。
- 线段树、分块
- 如果这个还不会那就不要做 Ynoi 了吧
- 基数排序
- 这个在 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(nnlogn) 的解法。
灵魂拷问:能 过 吗?
显然是不能的。
于是就有了——
33 本题低复杂度解法
我们发现复杂度有两个瓶颈:一是零散修改,二是整体查询。分开讨论怎么优化。
3.13.1 零散修改优化
真的有必要重构整棵线段树吗?
不要忘了:
- 线段树的子树还是线段树
- 这里的线段树支持整体加,不支持区间加
所以我们可以在零散修改的时候在终止节点上面打标记,非终止节点线性重构。
对于标记的下放,我们可以这样处理:我们在线段树上搞一个节点整体加的标记,这个是正常下放的;然后再在凸包上面维护一个凸包整体加的标记,这个标记是只叠加不下放的。取凸包内节点的时候考虑叠加的正比例函数对点的位置的影响即可。
因为每一层非终止节点的数量是 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}vlog10v 和 \log_2nlog2n 的差距不是很大,除 1010 又会有很大的常数。所以基数排序的基数取 20482048,这样可以位运算,\log_{2048}vlog2048v 也很小,速度就会快不少。
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;
}
}