这个死宅题面就不吐槽了。。。
2018目标:一定要让 nzhtl1477 n z h t l 1477 把罚抄打通!
这题当然是 O(nn−−√+nlogn) O ( n n + n l o g n )
先考虑全局最大子段和,全局加
O(nlogn)
O
(
n
l
o
g
n
)
怎么做。
考虑线段树,显然,如果我们每个区间维护一个答案函数
f(x)
f
(
x
)
表示加
x
x
时答案是多少,这题就做完了。
维护最大子段和,显然要维护三个函数:
pre(x),suf(x)
p
r
e
(
x
)
,
s
u
f
(
x
)
可以半平面交,由于斜率大于
0
0
,所以可以拿栈实现
除了由两个儿子的
ans(x)
a
n
s
(
x
)
合并而来,还可以用左儿子的
suf
s
u
f
,右儿子的
pre
p
r
e
合并。可以考虑维护双指针指向两个下凸壳,这样单调扫一遍与
ans
a
n
s
合并就行
回到原题,可以考虑分块,每块维护个线段树。
修改:对于中间的块,记 3 3 个指针指向三个分段函数,表示现在在哪一段,然后暴力。两边零散的块暴力在线段树上修改经过的区间。这样修改的长度之和是 O(n−−√) O ( n ) 的,因为每层常数个区间被修改。然后指针清零,这样每次只会增加 O(n−−√) O ( n ) 次指针增加机会,所以指针增加次数还是 O(nn−−√) O ( n n )
询问:两边零散的块暴力,
O(n−−√)
O
(
n
)
。中间的块:
1.
1.
答案在块里,用指针
O(1)
O
(
1
)
得到结果
2.
2.
答案跨越块。记一个
maxsuf
maxsuf
,每次更新与计算是
O(1)
O
(
1
)
的。记得
maxsuf=max(maxsuf,0)
maxsuf=max(maxsuf,0)
然后复杂度就是 O(nn−−√) O ( n n )
然而下列代码是被卡常的:(正确性倒是保证了)
#include<bits/stdc++.h>
#define BLK 520
#define maxn 100100
#define xx first
#define yy second
#define LK(x) ((x)*kuai)
#define RK(x) min((x+1)*kuai,n)
using namespace std;
typedef long long ll;
typedef pair<ll,ll> par;
par mem[maxn*80],*ptr=mem,tmp1[maxn<<2],tmp2[maxn<<2],sta[maxn<<2],lxldl;
// AxB<CxD judge!
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
char ch=nc();
register int sum=0,f=0;
while(!(ch>='0'&&ch<='9')&&ch!='-')ch=nc();
if(ch=='-')f=1,ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return f?-sum:sum;
}
inline ll max(const ll& a,const ll& b){
return a<b?b:a;
}
inline int jdg(par A,par B,par C,par D){
ll a=(A.yy-B.yy)*(D.xx-C.xx);
ll b=(C.yy-D.yy)*(B.xx-A.xx);
return a==b?0:(a<b?-1:1);
}
inline ll cal(par A,ll x){
return A.xx*x+A.yy;
}
par inline _sum(par a,par b){
return par(a.xx+b.xx,a.yy+b.yy);
}
bool inline cmp(par a,par b){
return a.xx<b.xx||(a.xx==b.xx&&a.yy>b.yy);
}
struct WXHGGG{
par *a;
int size;
void inline cp(par* bg,par* ed){size=ed-bg,memcpy(a,bg,sizeof(par)*size);}
void inline cp(par* bg,int& sz){sz=size,memcpy(bg,a,sizeof(par)*size);}
void inline rewrite(ll atg){
int p;
for(p=0;p+1<size&&cal(a[p],atg)<cal(a[p+1],atg);)p++;
for(int i=p;i<size;++i)a[i].yy+=a[i].xx*atg,a[i-p]=a[i];
size-=p;
}
void print(){
printf("\n{size=%d}",size);
for(int i=0;i<size;++i)printf("[%lld,%lld]",a[i].xx,a[i].yy);
puts("");
}
};
void inline LXLDuliu(int& tp,par lxldl){
if(tp&&lxldl.xx==sta[tp-1].xx){
sta[tp-1].yy=max(sta[tp-1].yy,lxldl.yy);
return ;
}
while(tp>1&&jdg(sta[tp-2],sta[tp-1],sta[tp-1],lxldl)>=0)tp--;
sta[tp++]=lxldl;
}
#pragma pack(1)
struct WXHTBQ{
WXHGGG pre[1025],suf[1025],ans[1025];
ll sum[1025],a[BLK],atg[1025],alltg;
int n,len[1025],pans,ppre,psuf;
void upd(int o){
int tp=0,ls=o<<1,rs=o<<1|1;
//merge pre
pre[ls].cp(sta,tp);
for(int i=0;i<pre[rs].size;++i){
lxldl=par(len[ls]+pre[rs].a[i].xx,sum[ls]+pre[rs].a[i].yy);
LXLDuliu(tp,lxldl);
}
pre[o].cp(sta,sta+tp),tp=0;
//merge suf
suf[rs].cp(sta,tp);
for(int i=0;i<suf[ls].size;++i){
lxldl=par(len[rs]+suf[ls].a[i].xx,sum[rs]+suf[ls].a[i].yy);
LXLDuliu(tp,lxldl);
}
suf[o].cp(sta,sta+tp);
int tp1=0,tp2=0;
//merge ans
for(int lxl,dl=0,i=0,j=0;i<suf[ls].size-1||j<pre[rs].size-1;){
tmp1[tp1++]=_sum(suf[ls].a[i],pre[rs].a[j]);
if(i==suf[ls].size-1)j++;
else if(j==pre[rs].size-1)i++;
else lxl=jdg(suf[ls].a[i],suf[ls].a[i+1],pre[rs].a[j],pre[rs].a[j+1]),i+=(lxl<=dl),j+=(lxl>=dl);
}
tmp1[tp1++]=_sum(suf[ls].a[suf[ls].size-1],pre[rs].a[pre[rs].size-1]);
for(int lxl,dl=0,i=0,j=0;i<ans[ls].size||j<ans[rs].size;){
if(i==ans[ls].size)tmp2[tp2++]=ans[rs].a[j++];
else if(j==ans[rs].size)tmp2[tp2++]=ans[ls].a[i++];
else if(cmp(ans[ls].a[i],ans[rs].a[j]))tmp2[tp2++]=ans[ls].a[i++];
else tmp2[tp2++]=ans[rs].a[j++];
}
tp=0;
for(int lxl,dl=0,i=0,j=0;i<tp1||j<tp2;){
if(i==tp1)lxldl=tmp2[j++];
else if(j==tp2)lxldl=tmp1[i++];
else if(cmp(tmp1[i],tmp2[j]))lxldl=tmp1[i++];
else lxldl=tmp2[j++];
LXLDuliu(tp,lxldl);
}
ans[o].cp(sta,sta+tp);
sum[o]=sum[o<<1]+sum[o<<1|1];
}
void build(int o,int l,int r){
pre[o].a=ptr,ptr+=r-l+1;
suf[o].a=ptr,ptr+=r-l+1;
pre[o].size=suf[o].size=ans[o].size=0;
ans[o].a=ptr,ptr+=r-l+1;
len[o]=r-l+1;
if(l==r){
sum[o]=a[l];
pre[o].a[0]=suf[o].a[0]=par(1,a[l]);
ans[o].a[0]=par(1,a[l]);
pre[o].size=suf[o].size=ans[o].size=1;
return ;
}
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
upd(o);
}
void rewrite(int o,ll A){
pre[o].rewrite(A);
suf[o].rewrite(A);
ans[o].rewrite(A);
}
void mdy(int o,int l,int r,int ql,int qr,ll A){
if(ql<=l&&r<=qr){
rewrite(o,A);
sum[o]+=A*len[o],atg[o]+=A;
return ;
}
int mid=l+r>>1;
if(atg[o]){
atg[o<<1]+=atg[o],sum[o<<1]+=len[o<<1]*atg[o];
atg[o<<1|1]+=atg[o],sum[o<<1|1]+=len[o<<1|1]*atg[o];
rewrite(o<<1,atg[o]),rewrite(o<<1|1,atg[o]);
}
if(ql<=mid)mdy(o<<1,l,mid,ql,qr,A);
if(qr>mid)mdy(o<<1|1,mid+1,r,ql,qr,A);
atg[o]=0,upd(o);
}
void shift(ll tg){
atg[1]+=tg,alltg+=tg,sum[1]+=len[1]*tg;
while(pans+1<ans[1].size&&cal(ans[1].a[pans],alltg)<cal(ans[1].a[pans+1],alltg))pans++;
while(ppre+1<pre[1].size&&cal(pre[1].a[ppre],alltg)<cal(pre[1].a[ppre+1],alltg))ppre++;
while(psuf+1<suf[1].size&&cal(suf[1].a[psuf],alltg)<cal(suf[1].a[psuf+1],alltg))psuf++;
}
void init(ll* bg,ll* ed){
n=ed-bg;
for(int i=0;i<n;++i)a[i]=bg[i];
build(1,0,n-1);
}
void pd(ll* a){
pans=ppre=psuf=0;
for(int i=0;i<n;++i)a[i]+=alltg;
rewrite(1,alltg);
alltg=0;
}
#define ANS 1
#define PRE 2
#define SUF 3
ll kagari(ll* a,ll* b,int FLAG){
ll mn=0,nw=0,ans=0;
if(FLAG==ANS)for(int i=0;i<b-a;++i)
nw+=a[i]+alltg,mn=min(mn,nw),ans=max(ans,nw-mn);
else if(FLAG==PRE)for(int i=0;i<b-a;++i)
nw+=a[i]+alltg,ans=max(ans,nw);
else for(int i=b-a-1;i>=0;--i)
nw+=a[i]+alltg,ans=max(ans,nw);
return ans;
}
}s[BLK];
int kuai,n,m;
ll a[maxn];
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
n=rd(),m=rd();
for(int i=0;i<n;++i)a[i]=rd();
kuai=450;
int _m=(n+kuai-1)/kuai;
for(int i=0;i<_m;++i)s[i].init(a+LK(i),a+RK(i)),s[i].shift(0);
for(int i=0,op,l,r,x;i<m;++i){
op=rd(),l=rd(),r=rd();
l--,r--;
if(op==1){
x=rd();
int bl=l/kuai,br=r/kuai;
if(bl==br){
s[bl].pd(a+LK(bl));
for(int i=l;i<=r;++i)a[i]+=x;
s[bl].mdy(1,0,s[bl].n-1,l%kuai,r%kuai,x);
s[bl].shift(0);
} else {
if(l==LK(bl))s[bl].shift(x);
else {
s[bl].pd(a+LK(bl));
for(int i=l;i<RK(bl);++i)a[i]+=x;
s[bl].mdy(1,0,s[bl].n-1,l%kuai,s[bl].n-1,x);
s[bl].shift(0);
}
if(r==RK(br)-1)s[br].shift(x);
else {
s[br].pd(a+LK(br));
for(int i=LK(br);i<=r;++i)a[i]+=x;
s[br].mdy(1,0,s[br].n-1,0,r%kuai,x);
s[br].shift(0);
}
for(int j=bl+1;j<br;++j)s[j].shift(x);
}
} else {
int bl=l/kuai,br=r/kuai;
if(bl==br){
printf("%lld\n",max(0ll,s[bl].kagari(a+l,a+r+1,ANS)));
} else {
ll ans=max(s[bl].kagari(a+l,a+RK(bl),ANS),s[br].kagari(a+LK(br),a+r+1,ANS));
ll sum=s[bl].kagari(a+l,a+RK(bl),SUF);
for(int i=bl+1;i<br;++i)
ans=max(ans,cal(s[i].pre[1].a[s[i].ppre],s[i].alltg)+sum),
ans=max(ans,cal(s[i].ans[1].a[s[i].pans],s[i].alltg)),
sum+=s[i].sum[1],sum=max(sum,cal(s[i].suf[1].a[s[i].psuf],s[i].alltg)),
sum=max(sum,0ll);
ans=max(ans,sum+s[br].kagari(a+LK(br),a+r+1,PRE));
printf("%lld\n",max(0ll,ans));
}
}
}
}
UPD:卡常大成功!秘诀:将线段树根节点的内存分配在一起,rewrite次数可以优化,merge ans的时候可以先把两边压到栈里再归并
实际上前2个最有用,因为BZOJ老爷机内存访问巨慢。。。
#include<bits/stdc++.h>
#define BLK 460
#define maxn 100100
#define xx first
#define yy second
#define LK(x) ((x)*kuai)
#define RK(x) min((x+1)*kuai,n)
using namespace std;
typedef long long ll;
typedef pair<ll,ll> par;
char outbuf[1<<24],*O=outbuf;
par mem[maxn*70],*ptr=mem,*nptr=mem,tmp1[maxn<<2],tmp2[maxn<<2],tmp3[maxn<<2],sta[maxn<<2],lxldl;
// AxB<CxD judge!
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
register int sum=0,f=0;
// scanf("%d",&sum);
// return sum;
char ch=nc();
while(!(ch>='0'&&ch<='9')&&ch!='-')ch=nc();
if(ch=='-')f=1,ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return f?-sum:sum;
}
void print(ll x){
if(!x)*O++='0';
static char s[100],*t=s;
ll y=0;
while(x)y=x/10,*t++=x-10*y+'0',x=y;
while(t!=s)*O++=*--t;
*O++='\n';
}
inline ll max(const ll& a,const ll& b){
return a<b?b:a;
}
inline int jdg(par A,par B,par C,par D){
ll a=(A.yy-B.yy)*(D.xx-C.xx);
ll b=(C.yy-D.yy)*(B.xx-A.xx);
return a==b?0:(a<b?-1:1);
}
inline ll cal(par A,ll x){
return A.xx*x+A.yy;
}
par inline _sum(par a,par b){
return par(a.xx+b.xx,a.yy+b.yy);
}
bool inline cmp(par a,par b){
return a.xx<b.xx||(a.xx==b.xx&&a.yy>b.yy);
}
struct WXHGGG{
par *a;
int size;
void cp(par* bg,par* ed){size=ed-bg,memcpy(a,bg,sizeof(par)*size);}
void cp(par* bg,int& sz){sz=size,memcpy(bg,a,sizeof(par)*size);}
void rewrite(ll atg){
int p;
for(p=0;p+1<size&&cal(a[p],atg)<cal(a[p+1],atg);)p++;
for(int i=p;i<size;++i)a[i].yy+=a[i].xx*atg,a[i-p]=a[i];
size-=p;
}
void print(){
printf("\n{size=%d}",size);
for(int i=0;i<size;++i)printf("[%lld,%lld]",a[i].xx,a[i].yy);
puts("");
}
};
void inline LXLDuliu(int& tp,par lxldl,par* sta=::sta){
if(tp&&lxldl.xx==sta[tp-1].xx){
sta[tp-1].yy=max(sta[tp-1].yy,lxldl.yy);
return ;
}
while(tp>1&&jdg(sta[tp-2],sta[tp-1],sta[tp-1],lxldl)>=0)tp--;
sta[tp++]=lxldl;
}
struct WXHTBQ{
WXHGGG pre[BLK<<2],suf[BLK<<2],ans[BLK<<2];
ll a[BLK],sum[BLK<<2],atg[BLK<<2],alltg,_pans,_ppre,_psuf;
int n,len[BLK<<2],pans,ppre,psuf;
void upd(int o){
int tp=0,ls=o<<1,rs=o<<1|1;
//merge pre
pre[ls].cp(sta,tp);
for(int i=0;i<pre[rs].size;++i){
lxldl=par(len[ls]+pre[rs].a[i].xx,sum[ls]+pre[rs].a[i].yy);
LXLDuliu(tp,lxldl);
}
pre[o].cp(sta,sta+tp),tp=0;
//merge suf
suf[rs].cp(sta,tp);
for(int i=0;i<suf[ls].size;++i){
lxldl=par(len[rs]+suf[ls].a[i].xx,sum[rs]+suf[ls].a[i].yy);
LXLDuliu(tp,lxldl);
}
suf[o].cp(sta,sta+tp);
int tp1=0,tp2=0;
//merge ans
for(int lxl,dl=0,i=0,j=0;i<suf[ls].size-1||j<pre[rs].size-1;){
tmp1[tp1++]=_sum(suf[ls].a[i],pre[rs].a[j]);
if(i==suf[ls].size-1)j++;
else if(j==pre[rs].size-1)i++;
else lxl=jdg(suf[ls].a[i],suf[ls].a[i+1],pre[rs].a[j],pre[rs].a[j+1]),i+=(lxl<=dl),j+=(lxl>=dl);
}
tmp1[tp1++]=_sum(suf[ls].a[suf[ls].size-1],pre[rs].a[pre[rs].size-1]);
for(int lxl,dl=0,i=0,j=0;i<ans[ls].size||j<ans[rs].size;){
if(i==ans[ls].size)lxldl=ans[rs].a[j++];
else if(j==ans[rs].size)lxldl=ans[ls].a[i++];
else if(cmp(ans[ls].a[i],ans[rs].a[j]))lxldl=ans[ls].a[i++];
else lxldl=ans[rs].a[j++];
LXLDuliu(tp2,lxldl,tmp2);
}
tp=0;
for(int lxl,dl=0,i=0,j=0;i<tp1||j<tp2;){
if(i==tp1)lxldl=tmp2[j++];
else if(j==tp2)lxldl=tmp1[i++];
else if(cmp(tmp1[i],tmp2[j]))lxldl=tmp1[i++];
else lxldl=tmp2[j++];
LXLDuliu(tp,lxldl);
}
ans[o].cp(sta,sta+tp);
sum[o]=sum[o<<1]+sum[o<<1|1];
}
void build(int o,int l,int r){
if(o>1){
pre[o].a=ptr,ptr+=r-l+1;
suf[o].a=ptr,ptr+=r-l+1;
ans[o].a=ptr,ptr+=r-l+1;
} else {
pre[o].a=nptr,nptr+=r-l+1;
suf[o].a=nptr,nptr+=r-l+1;
ans[o].a=nptr,nptr+=r-l+1;
}
pre[o].size=suf[o].size=ans[o].size=0;
len[o]=r-l+1;
if(l==r){
sum[o]=a[l];
pre[o].a[0]=suf[o].a[0]=par(1,a[l]);
ans[o].a[0]=par(1,a[l]);
pre[o].size=suf[o].size=ans[o].size=1;
return ;
}
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
upd(o);
}
void rewrite(int o,ll A){
pre[o].rewrite(A);
suf[o].rewrite(A);
ans[o].rewrite(A);
}
void mdy(int o,int l,int r,int ql,int qr,ll A,ll tg=0){
if(ql<=l&&r<=qr){
rewrite(o,A+tg);
sum[o]+=A*len[o],atg[o]+=A;
return ;
}
int mid=l+r>>1;
if(atg[o]){
atg[o<<1]+=atg[o],sum[o<<1]+=len[o<<1]*atg[o];
atg[o<<1|1]+=atg[o],sum[o<<1|1]+=len[o<<1|1]*atg[o];
if(ql>mid)rewrite(o<<1,atg[o]);
if(qr<=mid)rewrite(o<<1|1,atg[o]);
}
if(ql<=mid)mdy(o<<1,l,mid,ql,qr,A,atg[o]);
if(qr>mid)mdy(o<<1|1,mid+1,r,ql,qr,A,atg[o]);
atg[o]=0,upd(o);
}
void shift(ll tg){
atg[1]+=tg,alltg+=tg,sum[1]+=len[1]*tg;
while(pans+1<ans[1].size&&cal(ans[1].a[pans],alltg)<cal(ans[1].a[pans+1],alltg))pans++;
while(ppre+1<pre[1].size&&cal(pre[1].a[ppre],alltg)<cal(pre[1].a[ppre+1],alltg))ppre++;
while(psuf+1<suf[1].size&&cal(suf[1].a[psuf],alltg)<cal(suf[1].a[psuf+1],alltg))psuf++;
_pans=cal(ans[1].a[pans],alltg);
_ppre=cal(pre[1].a[ppre],alltg);
_psuf=cal(suf[1].a[psuf],alltg);
}
void init(ll* bg,ll* ed){
n=ed-bg;
for(int i=0;i<n;++i)a[i]=bg[i];
build(1,0,n-1);
}
void pd(ll* a){
pans=ppre=psuf=0;
for(int i=0;i<n;++i)a[i]+=alltg;
rewrite(1,alltg);
alltg=0;
}
#define ANS 1
#define PRE 2
#define SUF 3
ll kagari(ll* a,ll* b,int FLAG){
ll mn=0,nw=0,ans=0;
if(FLAG==ANS)for(int i=0;i<b-a;++i)
nw+=a[i]+alltg,mn=min(mn,nw),ans=max(ans,nw-mn);
else if(FLAG==PRE)for(int i=0;i<b-a;++i)
nw+=a[i]+alltg,ans=max(ans,nw);
else for(int i=b-a-1;i>=0;--i)
nw+=a[i]+alltg,ans=max(ans,nw);
return ans;
}
}s[BLK];
int kuai,n,m;
ll a[maxn];
inline int rd2(){
char ch=nc();
while(!(ch>='A'&&ch<='Z'))ch=nc();
return ch=='A'?1:2;
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
n=rd(),m=rd();
for(int i=0;i<n;++i)a[i]=rd();
kuai=450;
ptr+=3*n;
int _m=(n+kuai-1)/kuai;
for(int i=0;i<_m;++i)s[i].init(a+LK(i),a+RK(i)),s[i].shift(0);
for(int i=0,op,l,r,x;i<m;++i){
op=rd(),l=rd(),r=rd();
l--,r--;
if(op==1){
x=rd();
int bl=l/kuai,br=r/kuai;
if(bl==br){
s[bl].pd(a+LK(bl));
for(int i=l;i<=r;++i)a[i]+=x;
s[bl].mdy(1,0,s[bl].n-1,l%kuai,r%kuai,x);
s[bl].shift(0);
} else {
if(l==LK(bl))s[bl].shift(x);
else {
s[bl].pd(a+LK(bl));
for(int i=l;i<RK(bl);++i)a[i]+=x;
s[bl].mdy(1,0,s[bl].n-1,l%kuai,s[bl].n-1,x);
s[bl].shift(0);
}
for(int j=bl+1;j<br;++j)s[j].shift(x);
if(r==RK(br)-1)s[br].shift(x);
else {
s[br].pd(a+LK(br));
for(int i=LK(br);i<=r;++i)a[i]+=x;
s[br].mdy(1,0,s[br].n-1,0,r%kuai,x);
s[br].shift(0);
}
}
} else {
int bl=l/kuai,br=r/kuai;
if(bl==br){
print(max(0ll,s[bl].kagari(a+l,a+r+1,ANS)));
} else {
ll ans=max(s[bl].kagari(a+l,a+RK(bl),ANS),s[br].kagari(a+LK(br),a+r+1,ANS));
ll sum=s[bl].kagari(a+l,a+RK(bl),SUF);
for(int i=bl+1;i<br;++i)
ans=max(ans,s[i]._ppre+sum),
ans=max(ans,s[i]._pans),
sum+=s[i].sum[1],sum=max(sum,s[i]._psuf),
sum=max(sum,0ll);
ans=max(ans,sum+s[br].kagari(a+LK(br),a+r+1,PRE));
print(max(0ll,ans));
}
}
}
fwrite(outbuf,1,O-outbuf,stdout);
}