常数不想卡了。。。。。。
题目要全局加和区间最大子段和。
单点加和区间最大子段和可以维护前缀/后缀max和,总体和,最大子段和解决。
现在要求全局加也能这样维护。
但是实际上一个前缀/后缀在加了一定程度后可能不再是答案。比较麻烦。
解决方法:
我们想要快速寻找到一些后缀的最优决策点。
假设当前的后缀长度为$k$,值为$b$
根据题意,加了以后的值就为$kx+b$,其实就是一条直线。
这个比较难维护(原因见后)。可以把这个后缀化成一个点$(x,y)$,如果全局加了$x$,则答案就是一条直线$-x$切这个凸包,且询问最大截距。
答案必须要在凸包上。可以建出凸包。
这样子成功维护了前/后缀的答案。
但是全局答案十分难维护。
当前节点x的全局答案就是它的左/右子树内部的全局答案的凸包,再加上线段树左半边取出的任意一个点$(x,y)$和右半边取出任意的点$(a,b)$的$(x+y,a+b)$这些点组成的凸包。
每一个节点上取出左/右子树如果从线段树每一个节点上取出左/右子树取出后/前缀暴力合并再求凸包,时间复杂度高达$O(n^2)$,不可接受。
注意到答案就是左/右子树的后/前缀的闵可夫斯基和加上左/右子树的答案,所以对左/右节点的凸包求闵可夫斯基和即可。
如果在线段树询问定位到的节点的每个凸包上二分,则时间复杂度为$O((n+m)\log^2_2n)$,很难过。
可以把所有点按照询问的全局加值从小到大排序,这样子最优决策点就是单调增加的,时间复杂度降为$O((n+m)\log_2n)$
代码比较难写。
下面的代码由于常数原因只能获得10分,但是正确性有保障。
#includeusing namespace std; #define int long long #define N 1200010 struct no{ int x,y; }st[N],tv[N]; int tp,n,m,a[N],ct,ans[N],s[N],mx[N]; no operator +(no x,no y){ return (no){x.x+y.x,x.y+y.y}; } no operator -(no x,no y){ return (no){x.x-y.x,x.y-y.y}; } int operator <=(no x,no y){ return x.y*y.x<=x.x*y.y; } int rd(){ int v=0,op=1; char c=getchar(); while(!isdigit(c)&&c!='-') c=getchar(); if(c=='-'){ op=-op; c=getchar(); } while(isdigit(c)){ v=v*10+c-'0'; c=getchar(); } return v*op; } struct hl{ vector a; int p,v; void ad(no x){ a.push_back(x); v++; } void bd(){ tp=0; for(int i=0;i ){ if(!tp){ st[tp++]=a[i]; continue; } if(tp&&st[tp-1].x==a[i].x){ if(st[tp-1].y<=a[i].y){ tp--; st[tp++]=a[i]; } continue; } while(tp>1&&(st[tp-1]-st[tp-2])<=(a[i]-st[tp-2])) tp--; st[tp++]=a[i]; } v=tp; a.resize(tp); for(int i=0;i ) a[i]=st[i]; } int fd(int x){ while(p+1 1].x*x+a[p+1].y) p++; return a[p].x*x+a[p].y; } }sh[N],ph[N],sv[N]; hl r; void deb(hl x){ for(no y:x.a) cout< ' '< '\n'; cout<<'\n'; } hl operator +(hl x,hl y){ //deb(x); //deb(y); r.p=r.v=0; r.a.clear(); r.ad(x.a[0]+y.a[0]); int i=0,j=0,ct=0; while(i+1 1<y.v){ if((y.a[j+1]-y.a[j])<=(x.a[i+1]-x.a[i])){ i++; r.ad(x.a[i]+y.a[j]); } else{ j++; r.ad(x.a[i]+y.a[j]); } } while(i+1<x.v){ i++; r.ad(x.a[i]+y.a[j]); } while(j+1<y.v){ j++; r.ad(x.a[i]+y.a[j]); } r.v=r.a.size(); //deb(r); return r; } struct qu{ int l,r,x,i; }q[N]; struct nc{ int ls,rs,s,mx; }; nc operator +(nc x,nc y){ nc r=(nc){0,0,0,0}; r.s=x.s+y.s; r.ls=max(x.ls,y.ls+x.s); r.ls=max(r.ls,0ll); r.rs=max(y.rs,x.rs+y.s); r.rs=max(r.rs,0ll); r.mx=max(x.mx,max(y.mx,x.rs+y.ls)); r.mx=max(r.mx,0ll); return r; } int operator <(qu x,qu y){ return x.x<y.x; } hl mg(hl x,hl y){ r.p=r.v=0; r.a.clear(); int i=0,j=0; while(i y.v){ if(x.a[i].x<y.a[j].x){ r.a.push_back(x.a[i]); i++; } else{ r.a.push_back(y.a[j]); j++; } } while(i<x.v){ r.a.push_back(x.a[i]); i++; } while(j<y.v){ r.a.push_back(y.a[j]); j++; } r.bd(); r.v=r.a.size(); return r; } void bd(int o,int l,int r){ if(l==r){ sh[o].ad((no){0,0}); sh[o].ad((no){1,a[l]}); ph[o].ad((no){0,0}); ph[o].ad((no){1,a[l]}); sv[o].ad((no){0,0}); sv[o].ad((no){1,a[l]}); s[o]=a[l]; return; } int md=(l+r)/2; bd(o*2,l,md); bd(o*2+1,md+1,r); int sg=0; sh[o].ad((no){0,0}); for(int i=r;i>=l;i--){ sg+=a[i]; sh[o].ad((no){r-i+1,sg}); } sg=0; ph[o].ad((no){0,0}); for(int i=l;i<=r;i++){ sg+=a[i]; ph[o].ad((no){i-l+1,sg}); } ph[o].bd(); sh[o].bd(); if(o==1){ o++; o--; } sv[o]=mg(mg(sv[o*2],sv[o*2+1]),sh[o*2]+ph[o*2+1]); //deb(sv[o]); s[o]=s[o*2]+s[o*2+1]; } nc qq(int o,int l,int r,int x,int y,int z){ if(r return (nc){0,0,0,0}; if(x<=l&&r<=y){ nc v=(nc){ph[o].fd(z),sh[o].fd(z),z*(r-l+1)+s[o],sv[o].fd(z)}; return v; } int md=(l+r)/2; nc r1=qq(o*2,l,md,x,y,z); nc r2=qq(o*2+1,md+1,r,x,y,z); return r1+r2; } signed main(){ //freopen("ww.out","r",stdin); //freopen("t.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++) a[i]=rd(); bd(1,1,n); int p=0; for(int i=1;i<=m;i++){ int t,x,y; t=rd(); if(t==1){ x=rd(); p+=x; } else{ x=rd(); y=rd(); q[++ct]={x,y,p,ct}; } } sort(q+1,q+ct+1); for(int i=1;i<=ct;i++) ans[q[i].i]=qq(1,1,n,q[i].l,q[i].r,q[i].x).mx; for(int i=1;i<=ct;i++) cout< '\n'; }