支持单点修改,维护最大子段和的线段树 补发一波
其实难就难在如何合并区间信息(但是我记得有学长讲过)
l(tr)表示包含左端点的最大子段和,r(tr)表示包含右端点的最大子段和,mx(tr)表示该区间的最大子段和,sum(tr)表示该区间的总和
ls表示左儿子,rs表示右儿子
inline void upd(int tr) { l(tr)=max(l(ls),sum(ls)+l(rs)); mx(tr)=max(max(mx(ls),mx(rs)),r(ls)+l(rs)); r(tr)=max(r(rs),sum(rs)+r(ls)); sum(tr)=sum(ls)+sum(rs); }
代码:
#include<cstdio> #include<iostream> #include<cstring> #define ll long long #define R register ll #define ls (tr<<1) #define rs (tr<<1|1) using namespace std; struct node{ ll mxl,mx,mxr,sum; #define l(i) t[i].mxl #define mx(i) t[i].mx #define r(i) t[i].mxr #define sum(i) t[i].sum }t[2000010]; int n,m; inline ll g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } inline void upd(int tr) { l(tr)=max(l(ls),sum(ls)+l(rs)); mx(tr)=max(max(mx(ls),mx(rs)),r(ls)+l(rs)); r(tr)=max(r(rs),sum(rs)+r(ls)); sum(tr)=sum(ls)+sum(rs); } inline void build(int tr,ll l,ll r) { if(l==r) {l(tr)=mx(tr)=r(tr)=sum(tr)=g(); return ;} R md=(l+r)>>1; build(ls,l,md),build(rs,md+1,r); upd(tr); } inline void inc(int tr,ll l,ll r,ll pos,ll d) { if(l==r) {mx(tr)=l(tr)=r(tr)=sum(tr)=d; return ;} R md=(l+r)>>1; if(pos>md) inc(rs,md+1,r,pos,d); else inc(ls,l,md,pos,d); upd(tr); } inline node query(int tr,ll l,ll r,ll LL,ll RR) { if(l==LL&&r==RR) return t[tr]; R md=(l+r)>>1; if(LL>md) return query(rs,md+1,r,LL,RR); else if(RR<md+1) return query(ls,l,md,LL,RR); register node x=query(ls,l,md,LL,md),y=query(rs,md+1,r,md+1,RR),ret; ret.mxl=max(x.mxl,x.sum+y.mxl); ret.mxr=max(y.mxr,x.mxr+y.sum); ret.mx=max(max(x.mx,y.mx),x.mxr+y.mxl); ret.sum=x.sum+y.sum; return ret; } signed main() { n=g(),m=g(); memset(t,0xcf,sizeof(t)); build(1,1,n); for(R i=1;i<=m;++i) { R k=g(),l=g(),r=g(); if(k&1) { if(r<l) swap(l,r); printf("%lld\n",query(1,1,n,l,r).mx); } else inc(1,1,n,l,r); } }
2019.04.09